Setup

library(ggplot2)
library(dplyr)
library(tidyr)
library(purrr)
source("/home/guestA/n70275b/work/rscripts/geomNorm.R")

# Helper function
#ggpoints <- function(x,...) 
#  ggplot(x,...) + geom_point(size=3,stroke=1) +
#  ggrepel::geom_text_repel(size=4) + theme_minimal() + mycolor

## ラベルあり
ggpoints <- function(x,...) 
  ggplot(x,...) + geom_point(stroke=1) +
  ggrepel::geom_text_repel(size=4) + theme_minimal() + mycolor

## ラベルなし
#ggpoints <- function(x,...) 
#  ggplot(x,...) + geom_point(stroke=1) + theme_minimal() + mycolor

print(sessionInfo(),locale=FALSE)
R version 4.0.1 (2020-06-06)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Red Hat Enterprise Linux

Matrix products: default
BLAS/LAPACK: /usr/local/intel2018_up1/compilers_and_libraries_2018.0.128/linux/mkl/lib/intel64_lin/libmkl_intel_lp64.so

attached base packages:
 [1] grid      stats4    parallel  stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] stringr_1.4.0                             hrbrthemes_0.8.0                          ggrepel_0.8.2                             ggpubr_0.4.0.999                         
 [5] gplots_3.0.4                              DESeq2_1.28.1                             GGally_2.0.0                              vcd_1.4-7                                
 [9] BiocParallel_1.22.0                       Matrix_1.2-18                             SummarizedExperiment_1.18.2               DelayedArray_0.14.1                      
[13] matrixStats_0.56.0                        motifmatchr_1.10.0                        org.Mm.eg.db_3.11.4                       TxDb.Mmusculus.UCSC.mm10.knownGene_3.10.0
[17] org.Hs.eg.db_3.11.4                       TxDb.Hsapiens.UCSC.hg19.knownGene_3.2.2   GenomicFeatures_1.40.1                    AnnotationDbi_1.50.3                     
[21] Biobase_2.48.0                            ChIPseeker_1.24.0                         clusterProfiler_3.16.0                    BSgenome.Mmusculus.UCSC.mm10_1.4.0       
[25] ggsignif_0.6.0                            chromVAR_1.10.0                           purrr_0.3.4                               RColorBrewer_1.1-2                       
[29] ggsci_2.9                                 readr_1.3.1                               tidyr_1.1.1                               dplyr_1.0.1                              
[33] ggplot2_3.3.2                             TFBSTools_1.26.0                          BSgenome_1.56.0                           rtracklayer_1.48.0                       
[37] Biostrings_2.56.0                         XVector_0.28.0                            GenomicRanges_1.40.0                      GenomeInfoDb_1.24.2                      
[41] IRanges_2.22.2                            S4Vectors_0.26.1                          BiocGenerics_0.34.0                      

loaded via a namespace (and not attached):
  [1] rappdirs_0.3.1              R.methodsS3_1.8.0           bit64_4.0.2                 knitr_1.29                  irlba_2.3.3                 R.utils_2.9.2              
  [7] data.table_1.13.0           KEGGREST_1.28.0             RCurl_1.98-1.2              generics_0.0.2              snow_0.4-3                  cowplot_1.0.0              
 [13] lambda.r_1.2.4              RSQLite_2.2.0               europepmc_0.4               bit_4.0.4                   enrichplot_1.8.1            xml2_1.3.2                 
 [19] httpuv_1.5.4                isoband_0.2.2               assertthat_0.2.1            DirichletMultinomial_1.30.0 viridis_0.5.1               xfun_0.16                  
 [25] hms_0.5.3                   evaluate_0.14               promises_1.1.1              fansi_0.4.1                 progress_1.2.2              caTools_1.18.0             
 [31] dbplyr_1.4.4                readxl_1.3.1                igraph_1.2.5                DBI_1.1.0                   geneplotter_1.66.0          htmlwidgets_1.5.1          
 [37] futile.logger_1.4.3         reshape_0.8.8               ellipsis_0.3.1              backports_1.1.8             annotate_1.66.0             biomaRt_2.44.1             
 [43] vctrs_0.3.2                 abind_1.4-5                 withr_2.2.0                 ggforce_0.3.2               triebeard_0.3.0             GenomicAlignments_1.24.0   
 [49] prettyunits_1.1.1           DOSE_3.14.0                 lazyeval_0.2.2              seqLogo_1.54.3              crayon_1.3.4                genefilter_1.70.0          
 [55] labeling_0.3                pkgconfig_2.0.3             tweenr_1.0.1                nlme_3.1-148                rlang_0.4.7                 lifecycle_0.2.0            
 [61] miniUI_0.1.1.1              downloader_0.4              extrafontdb_1.0             BiocFileCache_1.12.1        cellranger_1.1.0            polyclip_1.10-0            
 [67] lmtest_0.9-37               urltools_1.7.3              carData_3.0-4               boot_1.3-25                 zoo_1.8-8                   base64enc_0.1-3            
 [73] pheatmap_1.0.12             ggridges_0.5.2              png_0.1-7                   viridisLite_0.3.0           bitops_1.0-6                R.oo_1.23.0                
 [79] KernSmooth_2.23-17          blob_1.2.1                  qvalue_2.20.0               rstatix_0.6.0               gridGraphics_0.5-0          CNEr_1.24.0                
 [85] scales_1.1.1                memoise_1.1.0               magrittr_1.5                plyr_1.8.6                  gdata_2.18.0                zlibbioc_1.34.0            
 [91] compiler_4.0.1              scatterpie_0.1.4            plotrix_3.7-8               Rsamtools_2.4.0             cli_2.0.2                   formatR_1.7                
 [97] mgcv_1.8-31                 MASS_7.3-51.6               tidyselect_1.1.0            stringi_1.4.6               forcats_0.5.0               yaml_2.2.1                 
[103] GOSemSim_2.14.1             askpass_1.1                 locfit_1.5-9.4              fastmatch_1.1-0             tools_4.0.1                 rio_0.5.16                 
[109] rstudioapi_0.11             TFMPvalue_0.0.8             foreign_0.8-80              gridExtra_2.3               farver_2.0.3                ggraph_2.0.3               
[115] digest_0.6.25               rvcheck_0.1.8               BiocManager_1.30.10         FNN_1.1.3                   shiny_1.5.0                 pracma_2.2.9               
[121] Rcpp_1.0.5                  car_3.0-8                   broom_0.7.0                 later_1.1.0.1               gdtools_0.2.2               httr_1.4.2                 
[127] colorspace_1.4-1            XML_3.99-0.5                splines_4.0.1               uwot_0.1.8                  graphlayouts_0.7.0          ggplotify_0.0.5            
[133] systemfonts_0.2.3           plotly_4.9.2.1              xtable_1.8-4                jsonlite_1.7.0              futile.options_1.0.1        poweRlaw_0.70.6            
[139] tidygraph_1.2.0             R6_2.4.1                    pillar_1.4.6                htmltools_0.5.0             mime_0.9                    glue_1.4.1                 
[145] fastmap_1.0.1               DT_0.15                     fgsea_1.14.0                utf8_1.1.4                  lattice_0.20-41             tibble_3.0.3               
[151] curl_4.3                    gtools_3.8.2                Rttf2pt1_1.3.8              zip_2.1.0                   GO.db_3.11.4                openxlsx_4.1.5             
[157] openssl_1.4.2               survival_3.2-3              rmarkdown_2.3               munsell_0.5.0               DO.db_2.9                   GenomeInfoDbData_1.2.3     
[163] msigdbr_7.1.1               haven_2.3.1                 reshape2_1.4.4              gtable_0.3.0                extrafont_0.17             
select <- dplyr::select
count <- dplyr::count
rename <- dplyr::rename

Parameters

modify here

# Files


#deftable <- "~/akuwakado/kuwakado/BRBSeq/H3mm18_Dox_0432lane2/Final_Rserver_191203/deftable_BRB_noumi_new_190520_fin191205ver.txt" #Umi補正なし (BRB)

deftable <- "/home/guestA/o70578a/akuwakado/kuwakado/BRBSeq/H3mm18_Dox_0432lane2/Final_Last_Rserver_200811/deftable_BRB_noumi_new_190520_Last20200811ver.txt"

#deftable <- "~/akuwakado/kuwakado/BRBSeq/H3mm18_Dox_0432lane2/Final_Rserver_191203/deftable_BRB_noumi_new_190520_fin191205ver.txt" #Umi補正なし (BRB)


#deftable <- "deftable_BRB_noumi_new_190520.txt" #Umi補正なし (BRB)

#deftable <- "~/akuwakado/kuwakado/BRBSeq/H3mm18_Dox_0432lane2/deftable_BRB_noumi_new_190520.txt" #Umi補正なし (BRB)


## Data selection (filter rows of deftable)
#use <- quo(!grepl("^18",group) & (group != "Nc-minusTryd"))
#use <- quo(TRUE) # use all
use <- quo(type != "C2C12")

# Species specific parameters
species <- "Mus musculus"
biomartann <- "mmusculus_gene_ensembl"
maxchrom <- 19 # 19: mouse, 22: human


# Graphics
# aesthetic mapping of labels
#myaes <- aes(colour=enzyme,shape=leg,label=rep) 
#myaes <- aes(colour=growth,shape=type,size=count) #ラベルなし
#myaes <- aes(colour=growth,shape=type,label=replicate,size=count) #ラベルあり
#myaes <- aes(colour=enzyme,shape=leg,label=replicate) #ラベルあり
#myaes <- aes(colour=enzyme,shape=leg,label=factor(rep))
#myaes <- aes(colour=type, shape=revcro, label=read, size=count)
#myaes <- aes(colour=type, shape=revcro, label=read)

#myaes <- aes(colour=growth,shape=type,label=replicate,size=count) #ラベルあり
#myaes <- aes(colour=time,shape=type,size=count,label=replicate)
#myaes <- aes(colour=WT_KO_intact_CTX, shape=Day,size=count,label=f_m)

#myaes <- aes(colour=WT_KO_intact_CTX, shape=Day, label=f_m) #サイズを変えず
#myaes <- aes(colour=growth,shape=type,label=replicate,size=count) #ラベルあり
myaes <- aes(colour=time,shape=type,label=rep,size=count) #ラベルあり
myaes2 <- aes(colour=time,shape=type) #kuwa add

# color palette of points: See vignette("ggsci")
mycolor <- ggsci::scale_color_aaas()



# PCA/UMAP
scalerows <- TRUE # gene-wise scaling (pattern is the matter?)
ntop <- 500 # number of top-n genes with high variance
seed <- 123 # set another number if UMAP looks not good
n_nei <- 6  # number of neighboring data points in UMAP #ここをどうしたらいい?


# DESeq2
#model <- ~groupn+lead #dateも追加
#model <- ~leg + enzyme + leg:enzyme
#model <- ~type+growth#+type:growth
#model <- ~group+lead


#model <- ~group
#model <- ~type+growth+type:growth #これでは相互作用が入っていない
#model <- ~type+growth #これでは相互作用が入っていない


model <- ~group
#model <- ~type+growth+growth:type

fdr <- 0.1 # acceptable false discovery rate
lfcthreth <- log2(1) # threshold in abs(log2FC)

# controls should be placed in the right
contrast <- list(
  
  group_UI_Doxplus_vs_minus = c("group", "BRB_UI_DoxPlus", "BRB_UI_DoxMinus"),
  group_0h_Doxplus_vs_minus = c("group", "BRB_0h_DoxPlus", "BRB_0h_DoxMinus"),
  group_24h_Doxplus_vs_minus = c("group", "BRB_24h_DoxPlus", "BRB_24h_DoxMinus"),
  group_48h_Doxplus_vs_minus = c("group", "BRB_48h_DoxPlus", "BRB_48h_DoxMinus")
  
  
  #group_UI_Doxplus_vs_minus = c("group", "Doxplus_UI", "Doxminus_UI"),
  #group_Diff0h_Doxplus_vs_minus = c("group", "Doxplus_Diff0h", "Doxminus_Diff0h"),
  #group_Diff24h_Doxplus_vs_minus = c("group", "Doxplus_Diff24h", "Doxminus_Diff24h"),
  #group_Diff48h_Doxplus_vs_minus = c("group", "Doxplus_Diff48h", "Doxminus_Diff48h")
  
  
  #Intercept = list("Intercept"), # reference level
  #leg_LvsR = c("leg", "L", "R"),
  #enz_KvsC = c("enzyme","K","C")
  #legL.enzK = list("legL.enzymeK") # interaction
  
  #type_Doxplus_vs_minus = c("type", "Doxplus", "Doxminus")
)

Retrieve Biomart

if(!exists("e2g")){
  #ensembl <- biomaRt::useMart("ENSEMBL_MART_ENSEMBL",host="asia.ensembl.org")
  #ensembl <- biomaRt::useMart("ENSEMBL_MART_ENSEMBL",host="uswest.ensembl.org")
  ensembl <- biomaRt::useMart("ENSEMBL_MART_ENSEMBL",host="useast.ensembl.org")
  mart <- biomaRt::useDataset(biomartann,mart=ensembl)
  e2g <- biomaRt::getBM(attributes=c("ensembl_gene_id","external_gene_name",
    "gene_biotype","chromosome_name"), mart=mart) %>% as_tibble %>%
  rename(
    ens_gene = ensembl_gene_id,
    ext_gene = external_gene_name,
    biotype = gene_biotype,
    chr = chromosome_name
  )
}
annotate <- partial(right_join,e2g,by="ens_gene")

#-----#
nrow(e2g)
[1] 56305
#readr::write_csv(e2g,"ensemble_list_asia.csv")
#readr::write_csv(e2g,"ensemble_list_uswest.csv")
readr::write_csv(e2g,"ensemble_list_useast.csv")

Load counts

def <- readr::read_tsv(deftable) %>% filter(!!use)
Parsed with column specification:
cols(
  file = col_character(),
  sample0 = col_character(),
  barcode = col_character(),
  growth = col_character(),
  sample = col_character(),
  group = col_character(),
  time = col_character(),
  type = col_character(),
  seq = col_character(),
  rep = col_double()
)
print(def)

#def$growth <- factor(def$growth,levels =c("UI","Diff0h","Diff24h","Diff48h"))
#def$type <- factor(def$type,levels =c("Doxminus","Doxplus"))

#factor(def$growth,levels =c("UI","Diff0h","Diff24h","Diff48h"))
# [1] UI      UI      UI      UI      UI      UI      UI      UI      Diff0h  Diff0h  Diff0h  Diff0h  Diff0h  Diff0h  Diff0h  Diff0h  Diff24h Diff24h Diff24h Diff24h
#[21] Diff24h Diff24h Diff24h Diff24h Diff48h Diff48h Diff48h Diff48h Diff48h Diff48h Diff48h Diff48h
#Levels: UI Diff0h Diff24h Diff48h


####--- New ---#### (no UMI ?)
# Set reference levels according to the contrast
for(x in keep(contrast,is.character))
  def[[x[1]]] <- relevel(factor(def[[x[1]]]),x[3])

umi <- def$file %>% unique %>% tibble(file=.) %>% 
  dplyr::mutate(data=map(file,readr::read_tsv,progress=FALSE)) %>%
  unnest() %>% dplyr::rename(barcode=cell) %>%
  dplyr::inner_join(select(def,file,barcode,sample),.,c("file","barcode")) %>%
  select(-file,-barcode) %>% dplyr::rename(ens_gene=gene)
Parsed with column specification:
cols(
  gene = col_character(),
  cell = col_character(),
  count = col_double()
)
`cols` is now required when using unnest().
Please use `cols = c(data)`
print(umi)

## sample, barcode, file を忘れずに!

mat <- umi %>% annotate %>%
  dplyr::mutate(chr=factor(chr,c(1:maxchrom,"X","Y","MT"))) %>%
  filter(!is.na(chr)) %>% spread(sample,count,fill=0)

## to check read vias, this add read number as "n" column (2019/4/19)
def <- umi %>% count(sample,wt=count) %>% dplyr::inner_join(def,.) %>% dplyr::rename(count=n)
Joining, by = "sample"
####-----------#### 




# Set reference levels according to the contrast
#for(x in keep(contrast,is.character))
#  def[[x[1]]] <- relevel(factor(def[[x[1]]]),x[3])

#umi <- def$file %>% unique %>% tibble(file=.) %>% 
#  mutate(data=map(file,readr::read_tsv,progress=FALSE)) %>%
#  unnest() %>% dplyr::rename(barcode=cell) %>%
#  inner_join(select(def,file,barcode,sample),.,c("file","barcode")) %>%
#  select(-file,-barcode) %>% dplyr::rename(ens_gene=gene)

#mat <- umi %>% annotate %>%
#  mutate(chr=factor(chr,c(1:maxchrom,"X","Y","MT"))) %>%
#  filter(!is.na(chr)) %>% spread(sample,count,fill=0)

print(mat)

## to check read vias, this add read number as "n" column (2019/4/19)
#def <- umi %>% count(sample,wt=count) %>% inner_join(def,.) %>% dplyr::rename(count=n)

print(def)


##====================================##
# 確認 (20191204) 2つの値は一緒か?
# 生のデータカウント中の遺伝子総数

umi %>% group_by(ens_gene) %>% summarize %>% nrow()
`summarise()` ungrouping output (override with `.groups` argument)
[1] 21871
umi %>% spread(sample,count,fill=0) %>% nrow()
[1] 21871
mat %>% nrow()
[1] 21742
mat %>% filter(chr!="MT") %>% nrow() # MTなし
[1] 21707
# matでは、chr等が不明なものは省いている。
# DEGでは、さらにMTも省いている。
##====================================##

Reads breakdown

Total reads

bychr <- mat %>% select(-(1:3)) %>%
  gather("sample","count",-chr) %>%
  group_by(chr,sample) %>% summarise(total=sum(count)) %>% ungroup
`summarise()` regrouping output by 'chr' (override with `.groups` argument)
ggplot(bychr,aes(reorder(sample,dplyr::desc(sample)),total/1e6,fill=chr)) +
  theme_linedraw() + geom_bar(stat="identity") + coord_flip() +
  xlab("sample") + ylab("million reads") + ggsci::scale_fill_igv() +
  scale_x_discrete(limits = rev(levels(sample)))

NA
NA

Biotype

bt <- mat %>% select(-c(1,2,4)) %>% group_by(biotype) %>%
  summarise_all(sum) %>% filter_at(-1,any_vars(. > 1000))
bt %>% tibble::column_to_rownames("biotype") %>%
  as.matrix %>% t %>% mosaicplot(las=2,shade=TRUE)

Correlations

drop rows with all 0 -> +1/2 -> geom.scale -> log -> Pearson’s

matf <- mat %>% filter(chr!="MT") %>% filter_at(-(1:4),any_vars(. > 0))
X <- matf %>% select(-(1:4)) %>% as.matrix
rownames(X) <- matf$ens_gene
lX <- log(gscale(X+0.5))
R <- cor(lX); diag(R) <- NA
pheatmap::pheatmap(R,color=viridis::viridis(256))

Dimension reduction

# set scale=TRUE if the patterns (not level) is the matter
p <- prcomp(t(lX[rank(-apply(lX,1,var)) <= ntop,]),scale=scalerows,center=TRUE)
screeplot(p,las=2,main="Importance")

print(summary(p)$imp[,seq(min(10,ncol(X)))])
                            PC1      PC2      PC3      PC4      PC5      PC6      PC7      PC8      PC9     PC10
Standard deviation     15.29237 6.164198 4.042076 3.825442 3.469872 3.401714 3.278207 3.191635 3.138257 3.038142
Proportion of Variance  0.46771 0.075990 0.032680 0.029270 0.024080 0.023140 0.021490 0.020370 0.019700 0.018460
Cumulative Proportion   0.46771 0.543710 0.576380 0.605650 0.629730 0.652880 0.674370 0.694740 0.714440 0.732900
label <- def %>% filter(sample %in% colnames(X))
df <- data.frame(p$x) %>% as_tibble(rownames="sample") %>%
  inner_join(label,.) %>% select(-file)
Joining, by = "sample"
print(df)
ggpoints(df,modifyList(aes(PC1,PC2),myaes))

set.seed(seed)
um <- uwot::umap(p$x,n_nei,2)
df <- as_tibble(um) %>% rename(UMAP1=V1,UMAP2=V2) %>% bind_cols(df)
ggpoints(df,modifyList(aes(UMAP1,UMAP2),myaes))


print(df)

##  kuwakado 変更 ##
ggpoints <- function(x,...) 
  ggplot(x,...) + geom_point(stroke=1) + theme_minimal() + mycolor

#ggpoints(df,modifyList(aes(PC1,PC2),myaes2))
#set.seed(seed)
#um <- uwot::umap(p$x,n_nei,2)
#df <- as_tibble(um) %>% rename(UMAP1=V1,UMAP2=V2) %>% bind_cols(df)
#ggpoints(df,modifyList(aes(UMAP1,UMAP2),myaes2))
## ## ## ##

DESeq2

Fit model

dds <- DESeq2::DESeqDataSetFromMatrix(X[,label$sample],label,model)
converting counts to integer mode
dds <- DESeq2::DESeq(dds)
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
-- note: fitType='parametric', but the dispersion trend was not well captured by the
   function: y = a/x + b, and a local regression fit was automatically substituted.
   specify fitType='local' or 'mean' to avoid this message next time.
final dispersion estimates
fitting model and testing
#=====#

dds <- DESeq2::estimateSizeFactors(dds)
norm <- DESeq2::counts(dds,normalized=TRUE) #DEGを取った後のクラスタリングに使う。

normalizedcount <- as.data.frame(norm) %>% tibble::rownames_to_column("ens_gene") %>% as_tibble
readr::write_csv(normalizedcount, "./H3mm18KO_3T3_Dox_normCount.csv")

normalizedcount %>% inner_join(e2g, by = "ens_gene")  %>% dplyr::select("ens_gene","ext_gene", "biotype","chr", all_of(label$sample)) %>% readr::write_csv("./H3mm18KO_3T3_Dox_normCount_genename.csv")

#count_dds <- estimateSizeFactors(dds)
#counts(count_dds, normalized=TRUE)

####--- + size factors を書き出し ------------------####
as.data.frame(DESeq2::sizeFactors(dds))  %>% tibble::rownames_to_column("sample") %>% readr::write_csv("./H3mm18KO_3T3_Dox__sizefactors.csv")

vst => z score


vsd <- DESeq2::vst(dds) #normalized countが入っている。(vstかrlog)
Xd <- SummarizedExperiment::assay(vsd) # 全て選択(200326) 20190920を元に (191024)
Xs <- Xd %>% t %>% scale %>% t

zscore <- Xs %>% as.data.frame() %>% tibble::rownames_to_column("ens_gene") %>% as_tibble
zscore_type <- zscore  %>% annotate %>% dplyr::select("ens_gene","ext_gene", "biotype","chr", all_of(label$sample))



readr::write_csv(zscore, "H3mm18KO_3T3_Dox__zscore_all.csv")
readr::write_csv(zscore_type, "H3mm18KO_3T3_Dox__zscore_type_all.csv")

nrow(zscore_type)
[1] 21707

Diagnostics plot

DESeq2::sizeFactors(dds) %>%
  {tibble(sample=names(.),sizeFactor=.)} %>%
  ggplot(aes(sample,sizeFactor)) + theme_minimal() +
  geom_bar(stat="identity") + coord_flip()

DESeq2::plotDispEsts(dds)

Extract results

191205修正

res <- mapply(function(x)
  DESeq2::results(dds,x,lfcThreshold=lfcthreth,alpha=fdr)
,contrast)

print(fdr)
[1] 0.1
# 200811修正
re_all <- map(res,as_tibble,rownames="ens_gene") %>%
  tibble(aspect=factor(names(.),names(.)),data=.) %>%
  mutate(data=map(data,annotate)) %>%
  unnest(cols = "data")

re <- re_all %>% filter(padj<fdr) #191120修正 unnest() 


#re <- map(res,as_tibble,rownames="ens_gene") %>%
#  tibble(aspect=factor(names(.),names(.)),data=.) %>%
#  mutate(data=map(data,annotate)) %>%
#  unnest(cols = "data") %>% filter(padj<fdr) #191120修正 unnest() 

fc <- re %>% select(1:7) %>% spread(aspect,log2FoldChange,fill=0)

imap(res,~{
  cat(paste0("-- ",.y," --"))
  DESeq2::summary(.x) #191120修正 DESeq2::summary.DESeqResults(.x)
}) %>% invisible
-- group_UI_Doxplus_vs_minus --
out of 21707 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 3, 0.014%
LFC < 0 (down)     : 0, 0%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 0)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

-- group_0h_Doxplus_vs_minus --
out of 21707 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 34, 0.16%
LFC < 0 (down)     : 40, 0.18%
outliers [1]       : 0, 0%
low counts [2]     : 18938, 87%
(mean count < 41)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

-- group_24h_Doxplus_vs_minus --
out of 21707 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 39, 0.18%
LFC < 0 (down)     : 51, 0.23%
outliers [1]       : 0, 0%
low counts [2]     : 18096, 83%
(mean count < 31)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

-- group_48h_Doxplus_vs_minus --
out of 21707 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 42, 0.19%
LFC < 0 (down)     : 54, 0.25%
outliers [1]       : 0, 0%
low counts [2]     : 17255, 79%
(mean count < 24)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

GSEA

msig <- msigdbr::msigdbr(species)
fgsea_msig <- partial(fgsea::fgsea,with(msig,split(gene_symbol,gs_name)))
gscat <- msig %>% select(gs_name,gs_cat,gs_subcat) %>%
  distinct() %>% rename(pathway=gs_name)

#gsea <- re %>% filter(aspect!="Intercept") %>% group_by(aspect) %>%
#  summarise(l2fc=list(setNames(log2FoldChange,ext_gene))) %>%
#  mutate(gse=map(l2fc,fgsea_msig,nperm=10000,maxSize=500)) %>%
#  select(-l2fc) %>% unnest %>% arrange(-NES) %>% right_join(gscat,.) %>%
#  mutate(leadingEdge=map_chr(leadingEdge,paste,collapse=","))

# gsea 修正ver [20190621]
#gsea <- re %>% filter(aspect!="Intercept") %>% group_by(aspect) %>%
#  summarise(l2fc=list(setNames(log2FoldChange,ext_gene))) %>%
#  mutate(gse=map(l2fc,fgsea_msig,nperm=10000,maxSize=500)) %>%
#  select(-l2fc) %>% unnest %>% arrange(-NES) %>% right_join(gscat,.) %>%
#  mutate(leadingEdge=map_chr(leadingEdge,paste,collapse=",")) %>%
#  group_by(aspect,gs_cat,gs_subcat) %>%
#  mutate(padj=p.adjust(pval,"BH")) %>% ungroup()

# gsea 修正ver [20190627]
gsea <- re %>% filter(aspect!="Intercept") %>% group_by(aspect) %>%
  summarise(l2fc=list(setNames(log2FoldChange,ext_gene))) %>%
  filter(map(l2fc,length)>10) %>%
  mutate(gse=map(l2fc,fgsea_msig,nperm=10000,maxSize=500)) %>%
  select(-l2fc) %>% unnest %>% arrange(-NES) %>% right_join(gscat,.) %>%
  mutate(leadingEdge=map_chr(leadingEdge,paste,collapse=",")) %>%
  group_by(aspect,gs_cat,gs_subcat) %>%
  mutate(padj=p.adjust(pval,"BH")) %>% ungroup()
`summarise()` ungrouping output (override with `.groups` argument)
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
 警告メッセージ: 
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 警告メッセージ: 
 警告メッセージ: 
 base::options(global_options) で:  base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled

  警告メッセージ: 
 'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で:  base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled

  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
 警告メッセージ: 
 警告メッセージ: 
 base::options(global_options) で:  base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled

  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で:  警告メッセージ: 

  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
WARNING: ignoring environment value of R_HOME
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 警告メッセージ: 
 base::options(global_options) で:  base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled

  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 警告メッセージ: 
 base::options(global_options) で:  base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled

  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
 警告メッセージ: 
 base::options(global_options) で: 
  'options(stringsAsFactors = TRUE)' is deprecated and will be disabled
Joining, by = "pathway"
hallmark <- gsea %>% filter(gs_cat=="H") %>%
  mutate(pathway=sub("^HALLMARK_","",pathway)) %>% 
  group_by(aspect) %>% nest %>%
  mutate(plt=map2(data,aspect,~
    ggplot(.x,aes(reorder(pathway,NES),NES,fill=padj<0.1)) +
    ggtitle(.y) + xlab("Hallmark gene sets") +
    geom_bar(stat="identity") + theme_minimal() + coord_flip() +
    theme(legend.position = "none") + ggsci::scale_fill_aaas())
  )
print(hallmark$plt)
[[1]]

[[2]]

[[3]]

See MSigDB Collections: http://software.broadinstitute.org/gsea/msigdb/collections.jsp

Write-out tables


#csvfilepath <- "BRB0432lane2noumi_H3mm18_Dox"

if(exists("fc"))   readr::write_csv(fc,"./2gun/BRB0432lane2noumi_H3mm18_Dox_l2fc_fdr0p1__final191205_last200811.csv")
if(exists("re"))   readr::write_csv(re,"./2gun/BRB0432lane2noumi_H3mm18_Dox_results_fdr0p1__final191205_last200811.csv")
if(exists("re_all"))   readr::write_csv(re_all,"./2gun/BRB0432lane2noumi_H3mm18_Dox_resultsall_fdr0p1__final191205_last200811.csv")
if(exists("gsea")) readr::write_csv(gsea,"./2gun/BRB0432lane2noumi_H3mm18_Dox_gsea_fdr0p1__final191205_last200811.csv")

Write-out tables Hallmark

#gseaのHallmarkのみ書き出し
hallmark_gsea <- gsea %>% filter(gs_cat=="H") %>% mutate(pathway=sub("^HALLMARK_","",pathway)) %>% group_by(aspect)
if(exists("hallmark_gsea")) readr::write_csv(hallmark_gsea,"./2gun/BRB0432lane2noumi_H3mm18_Dox_hallmark_gsea_fdr0p1__final191205_last200811.csv")

MAplot

5*7 inch


#maplot <- DESeq2::plotMA(res$group_UI_Doxplus_vs_minus, ylim=c(-2,2))
#print(maplot)
maplot <- DESeq2::plotMA(res$group_UI_Doxplus_vs_minus, ylim=c(-4,4), main="UI_Doxplus_vs_minus")

print(maplot)
NULL
#maplot <- DESeq2::plotMA(res$group_Diff0h_Doxplus_vs_minus , ylim=c(-2,2))
#print(maplot)
maplot <- DESeq2::plotMA(res$group_0h_Doxplus_vs_minus, ylim=c(-4,4), main="0h_Doxplus_vs_minus")

print(maplot)
NULL
#maplot <- DESeq2::plotMA(res$group_Diff24h_Doxplus_vs_minus, ylim=c(-2,2))
#print(maplot)
maplot <- DESeq2::plotMA(res$group_24h_Doxplus_vs_minus, ylim=c(-4,4), main="24h_Doxplus_vs_minus")

print(maplot)
NULL
#maplot <- DESeq2::plotMA(res$group_Diff48h_Doxplus_vs_minus, ylim=c(-2,2))
#print(maplot)
maplot <- DESeq2::plotMA(res$group_48h_Doxplus_vs_minus, ylim=c(-4,4), main="48h_Doxplus_vs_minus")

print(maplot)
NULL

尤度比検定

###Fit model LRT (BRBと同じ設定) ATACのフォーマットを持ってきた

def_list_select <- def %>% mutate(time=factor(time, c("UI","0h","24h","48h"))) %>% mutate(type=factor(type, c("DoxMinus","DoxPlus")))

#def_list_select <- def %>% mutate(growth=factor(growth, c("UI","Diff0h","Diff24h","Diff48h"))) %>% mutate(type=factor(type, c("Doxminus","Doxplus")))

#def_list_select <- def

dds0 <- 0
dds1_2 <- 0
res1_2 <- 0


model_full <- ~growth*type # BRB
model_reduced <- ~growth # BRB

#model_full <- ~time*type # full model  (~growth*type # BRB)
#model_reduced <- ~time # reduced model (~growth # BRB)

colnames(X) #使用するサンプル
 [1] "BRB_0h_DoxMinus_1"  "BRB_0h_DoxMinus_2"  "BRB_0h_DoxMinus_3"  "BRB_0h_DoxMinus_4"  "BRB_0h_DoxPlus_1"   "BRB_0h_DoxPlus_2"   "BRB_0h_DoxPlus_3"   "BRB_0h_DoxPlus_4"  
 [9] "BRB_24h_DoxMinus_1" "BRB_24h_DoxMinus_2" "BRB_24h_DoxMinus_3" "BRB_24h_DoxMinus_4" "BRB_24h_DoxPlus_1"  "BRB_24h_DoxPlus_2"  "BRB_24h_DoxPlus_3"  "BRB_24h_DoxPlus_4" 
[17] "BRB_48h_DoxMinus_1" "BRB_48h_DoxMinus_2" "BRB_48h_DoxMinus_3" "BRB_48h_DoxMinus_4" "BRB_48h_DoxPlus_1"  "BRB_48h_DoxPlus_2"  "BRB_48h_DoxPlus_3"  "BRB_48h_DoxPlus_4" 
[25] "BRB_UI_DoxMinus_1"  "BRB_UI_DoxMinus_2"  "BRB_UI_DoxMinus_3"  "BRB_UI_DoxMinus_4"  "BRB_UI_DoxPlus_1"   "BRB_UI_DoxPlus_2"   "BRB_UI_DoxPlus_3"   "BRB_UI_DoxPlus_4"  
# full model
dds0_LRT <- DESeq2::DESeqDataSetFromMatrix(X[,def_list_select$sample],def_list_select,model_full)  #full model
converting counts to integer mode
some variables in design formula are characters, converting to factors
# reduced model
dds_LRT <- DESeq2::DESeq(dds0_LRT, test="LRT", reduced=model_reduced) #reduced model
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
-- note: fitType='parametric', but the dispersion trend was not well captured by the
   function: y = a/x + b, and a local regression fit was automatically substituted.
   specify fitType='local' or 'mean' to avoid this message next time.
final dispersion estimates
fitting model and testing
res_LRT <- DESeq2::results(dds_LRT)
res_LRT_fdr0p1 <- DESeq2::results(dds_LRT)  #クラスタリングに使用
res_LRT_fdr0p2 <- DESeq2::results(dds_LRT,alpha=0.2)

print(model.matrix(model_full, def_list_select)) #full model
   (Intercept) growthDiff24h growthDiff48h growthUI typeDoxPlus growthDiff24h:typeDoxPlus growthDiff48h:typeDoxPlus growthUI:typeDoxPlus
1            1             0             0        1           0                         0                         0                    0
2            1             0             0        1           0                         0                         0                    0
3            1             0             0        1           0                         0                         0                    0
4            1             0             0        1           0                         0                         0                    0
5            1             0             0        1           1                         0                         0                    1
6            1             0             0        1           1                         0                         0                    1
7            1             0             0        1           1                         0                         0                    1
8            1             0             0        1           1                         0                         0                    1
9            1             0             0        0           0                         0                         0                    0
10           1             0             0        0           0                         0                         0                    0
11           1             0             0        0           0                         0                         0                    0
12           1             0             0        0           0                         0                         0                    0
13           1             0             0        0           1                         0                         0                    0
14           1             0             0        0           1                         0                         0                    0
15           1             0             0        0           1                         0                         0                    0
16           1             0             0        0           1                         0                         0                    0
17           1             1             0        0           0                         0                         0                    0
18           1             1             0        0           0                         0                         0                    0
19           1             1             0        0           0                         0                         0                    0
20           1             1             0        0           0                         0                         0                    0
21           1             1             0        0           1                         1                         0                    0
22           1             1             0        0           1                         1                         0                    0
23           1             1             0        0           1                         1                         0                    0
24           1             1             0        0           1                         1                         0                    0
25           1             0             1        0           0                         0                         0                    0
26           1             0             1        0           0                         0                         0                    0
27           1             0             1        0           0                         0                         0                    0
28           1             0             1        0           0                         0                         0                    0
29           1             0             1        0           1                         0                         1                    0
30           1             0             1        0           1                         0                         1                    0
31           1             0             1        0           1                         0                         1                    0
32           1             0             1        0           1                         0                         1                    0
attr(,"assign")
[1] 0 1 1 1 2 3 3 3
attr(,"contrasts")
attr(,"contrasts")$growth
[1] "contr.treatment"

attr(,"contrasts")$type
[1] "contr.treatment"
print(model.matrix(model_reduced, def_list_select)) #reduced model
   (Intercept) growthDiff24h growthDiff48h growthUI
1            1             0             0        1
2            1             0             0        1
3            1             0             0        1
4            1             0             0        1
5            1             0             0        1
6            1             0             0        1
7            1             0             0        1
8            1             0             0        1
9            1             0             0        0
10           1             0             0        0
11           1             0             0        0
12           1             0             0        0
13           1             0             0        0
14           1             0             0        0
15           1             0             0        0
16           1             0             0        0
17           1             1             0        0
18           1             1             0        0
19           1             1             0        0
20           1             1             0        0
21           1             1             0        0
22           1             1             0        0
23           1             1             0        0
24           1             1             0        0
25           1             0             1        0
26           1             0             1        0
27           1             0             1        0
28           1             0             1        0
29           1             0             1        0
30           1             0             1        0
31           1             0             1        0
32           1             0             1        0
attr(,"assign")
[1] 0 1 1 1
attr(,"contrasts")
attr(,"contrasts")$growth
[1] "contr.treatment"
head(res_LRT[order(res_LRT$pvalue), ])
log2 fold change (MLE): growthUI.typeDoxPlus 
LRT p-value: '~ growth * type' vs '~ growth' 
DataFrame with 6 rows and 6 columns
                    baseMean log2FoldChange     lfcSE       stat      pvalue        padj
                   <numeric>      <numeric> <numeric>  <numeric>   <numeric>   <numeric>
ENSMUSG00000113980  902.4102       0.948565  0.361248 12465.0670 0.00000e+00 0.00000e+00
ENSMUSG00000108686   12.4124      -0.268131  1.551478   274.2590 3.85216e-58 2.07342e-54
ENSMUSG00000035783  990.6555       0.268978  0.107580   166.3410 6.37769e-35 2.28853e-31
ENSMUSG00000061723  362.9786       0.719623  0.666752   145.0557 2.33349e-30 6.27999e-27
ENSMUSG00000029304 1088.1244       0.158544  0.123811    83.7472 2.79716e-17 6.02228e-14
ENSMUSG00000028972   67.7825      -1.170201  0.298094    65.5466 1.97388e-13 3.54147e-10
DESeq2::summary(res_LRT_fdr0p1) #20191108修正

out of 21707 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 125, 0.58%
LFC < 0 (down)     : 101, 0.47%
outliers [1]       : 0, 0%
low counts [2]     : 10942, 50%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
DESeq2::summary(res_LRT_fdr0p2) #20191108修正

out of 21707 with nonzero total read count
adjusted p-value < 0.2
LFC > 0 (up)       : 202, 0.93%
LFC < 0 (down)     : 179, 0.82%
outliers [1]       : 0, 0%
low counts [2]     : 10942, 50%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
#DESeq2::summary.DESeqResults(res_LRT_fdr0p1)
#DESeq2::summary.DESeqResults(res_LRT_fdr0p2)

尤度比検定 結果

result LRT


folder_name_plot_path <- "./LRT/"
csvfilepath <- "BRB0432lane2noumi_H3mm18_Dox"

allres_LRT <- 0

#----- 全ての結果 -----#
allres_LRT <- as_tibble(res_LRT,rownames="ens_gene") %>% right_join(e2g,.)
Joining, by = "ens_gene"
file_path <- paste(folder_name_plot_path, "all__", csvfilepath, "_last200811.csv",sep="")
readr::write_csv(allres_LRT, file_path) # 全ての結果

nrow(allres_LRT)
[1] 21707
nrow(allres_LRT %>% filter(padj<0.1))
[1] 226
nrow(allres_LRT %>% filter(padj<0.2))
[1] 381
#----- fdr 0.1の結果 -----#
LRT_deglist_fdr0p1 <- as_tibble(res_LRT_fdr0p1,rownames="ens_gene") %>% right_join(e2g,.) %>% filter(padj<0.1) #クラスタリングに使用
Joining, by = "ens_gene"
file_path <- paste(folder_name_plot_path, "DEG_fdr0p1__", csvfilepath, "_last200811.csv",sep="") # 今回取得したDEGのリスト
readr::write_csv(LRT_deglist_fdr0p1, file_path) # 全ての結果
nrow(LRT_deglist_fdr0p1)
[1] 226
#----- fdr 0.2の結果 -----#
LRT_deglist_fdr0p2 <- as_tibble(res_LRT_fdr0p2,rownames="ens_gene") %>% right_join(e2g,.) %>% filter(padj<0.2)
Joining, by = "ens_gene"
file_path <- paste(folder_name_plot_path, "DEG_fdr0p2__", csvfilepath, "_last200811.csv",sep="") # 今回取得したDEGのリスト
readr::write_csv(LRT_deglist_fdr0p2, file_path) # 全ての結果
nrow(LRT_deglist_fdr0p2)
[1] 381
LRT_deglist_fdr0p2 <- NA

# BRBでは right_join(e2g,.)、ATACでは right_join(ensemble,.)

Clustering LRT

#20191205修正と作成

# 全てのデータ

#-- 上で実行 --#
#dds_LRT <- DESeq2::DESeq(dds0_LRT, test="LRT", reduced=model_reduced) #reduced model
#res_LRT <- DESeq2::results(dds_LRT)
#res_LRT_fdr0p1 <- DESeq2::results(dds_LRT)
#res_LRT_fdr0p2 <- DESeq2::results(dds_LRT,alpha=0.2)
#--------------#

#vsd_LRT <- DESeq2::vst(dds_LRT)

#Xd_LRT <- SummarizedExperiment::assay(vsd_LRT)[which(res_LRT_fdr0p1$padj<0.1),] #degのリスト #Xd <- SummarizedExperiment::assay(vsd)[which(res$padj<0.1),]
#Xs_LRT <- Xd_LRT %>% t %>% scale %>% t

#-- クラスタリングに使用したXd,Xsを書き出し --#
# 20191212作成 (あとで確認できるように)
# LRT_deglist_fdr0p1

#file_path <- paste(folder_name_plot_path, "clustering_vsdLRTall__", csvfilepath, ".csv",sep="") 
#SummarizedExperiment::assay(vsd_LRT) %>% as_tibble(rownames="ens_gene") %>% readr::write_csv(.,file_path)

#file_path <- paste(folder_name_plot_path, "clustering_XdLRTfdr0p1__", csvfilepath, ".csv",sep="") 
#Xd_LRT %>% as_tibble(rownames="ens_gene") %>% readr::write_csv(.,file_path) 
# これと同じ: SummarizedExperiment::assay(vsd_LRT) %>% as_tibble(rownames="ens_gene")  %>% filter(ens_gene %in% LRT_deglist_fdr0p1$ens_gene)

#--------#

#file_path <- paste(folder_name_plot_path, "clustering_XsLRTall__", csvfilepath, ".csv",sep="")
#SummarizedExperiment::assay(vsd_LRT) %>% t %>% scale %>% t %>% as_tibble(rownames="ens_gene") %>% readr::write_csv(.,file_path)

#file_path <- paste(folder_name_plot_path, "clustering_XsLRTfdr0p1__", csvfilepath, ".csv",sep="") 
#Xs_LRT %>% as_tibble(rownames="ens_gene") %>% readr::write_csv(.,file_path)
# これと同じ: SummarizedExperiment::assay(vsd_LRT) %>% t %>% scale %>% t %>% as_tibble(rownames="ens_gene") %>% filter(ens_gene %in% LRT_deglist_fdr0p1$ens_gene)
#---------------------------------------------#


zscore_type_LRT <- zscore_type %>% filter(ens_gene %in% LRT_deglist_fdr0p1$ens_gene)
nrow(zscore_type_LRT)
[1] 226
Xs_LRT <- zscore_type_LRT %>% dplyr::select(-ens_gene,-ext_gene, -biotype,-chr) %>% as.matrix()
rownames(Xs_LRT) <- zscore_type_LRT$ens_gene



##--------- clustering -----------#
set.seed(3)


km_LRT <- kmeans(Xs_LRT,4,nstart = 25,algorithm = "Lloyd")
 10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした  10 回の反復を行いましたが収束しませんでした 
kmc_LRT <- km_LRT$centers %>% as_tibble(rownames="cluster") %>% gather(sample,val,-cluster) %>% inner_join(def)
Joining, by = "sample"
#kmc_LRT_group <- kmc_LRT %>% mutate(growth=factor(growth, c("UI","Diff0h","Diff24h","Diff48h"))) %>% mutate(type=factor(type, c("Doxplus","Doxminus")))
#kmc_LRT_group <- kmc_LRT_group %>% mutate(time=case_when(growth=="UI" ~"UI",growth=="Diff0h"~"0h",growth=="Diff24h"~"24h",growth=="Diff48h"~"48h",TRUE~"error"))
#kmc_LRT_group <- kmc_LRT_group %>% mutate(time=factor(time, c("UI","0h","24h","48h")))

kmc_LRT_group <- kmc_LRT %>% mutate(time=factor(time, c("UI", "0h","24h","48h"))) %>% mutate(type=factor(type,c("DoxPlus","DoxMinus"))) %>% mutate(rep=factor(rep, c("1", "2", "3", "4")))


gggglabel <- paste("3T3 Dox +-, k-means","[1]",km_LRT$size[1],"[2]",km_LRT$size[2],"[3]",km_LRT$size[3],"[4]",km_LRT$size[4],sep=" ")


#------- size -------#

print(km_LRT$size)  #4つのクラスター [1] 47 55 94 33
[1] 42 54 93 37
rrres_LRT <- km_LRT$cluster %>% tibble(ens_gene=names(.),cluster=.) %>% right_join(e2g,.) %>% arrange(cluster)
Joining, by = "ens_gene"
file_path <- paste(folder_name_plot_path, "DEG_fdr0p1__", csvfilepath, "_kmeans4__kmeans_cluster.csv",sep="") 
readr::write_csv(rrres_LRT,file_path)

##------- PCA -------#

pcacluster_save <- prcomp(Xs_LRT)$x %>% as_tibble %>% select(PC1,PC2) %>% mutate(cluster=km_LRT$cluster) %>% ggplot(aes(PC1,PC2,colour=factor(cluster)))+geom_point(size=1.5,alpha=0.6)+coord_fixed()+theme_linedraw()+ggsci::scale_color_d3("category20")

file_path <- paste(folder_name_plot_path, "DEG_fdr0p1__", csvfilepath, "_kmeans4__kmeans__pcacluster_PC1PC2.pdf",sep="") 
ggsave(plot=pcacluster_save,file=file_path, width = 10, height = 6, dpi = 120)
print(pcacluster_save)

pcacluster_save <- prcomp(Xs_LRT)$x %>% as_tibble %>% select(PC1,PC3) %>% mutate(cluster=km_LRT$cluster) %>% ggplot(aes(PC1,PC3,colour=factor(cluster)))+geom_point(size=1.5,alpha=0.6)+coord_fixed()+theme_linedraw()+ggsci::scale_color_d3("category20")

file_path <- paste(folder_name_plot_path, "DEG_fdr0p1__", csvfilepath, "_kmeans4__kmeans__pcacluster_PC1PC3.pdf",sep="") 
ggsave(plot=pcacluster_save,file=file_path, width = 10, height = 6, dpi = 120)

print(pcacluster_save)


#================================================#
# mouseCTX 0438を参考に。

#------------------#
f_cluster <- function(x) x %>% group_by(group, type, time, cluster) %>% summarise(avg=mean(val),se=sd(val)/sqrt(length(val))) %>% ungroup()
print(kmc_LRT_group %>% group_by(group, type, time) %>% summarise())
`summarise()` regrouping output by 'group', 'type' (override with `.groups` argument)
f_clusterp <- function(x) x %>% group_by(group, type, time, cluster) %>% summarise(avg=mean(val),se=sd(val)/sqrt(length(val))) %>% ungroup()
print(kmc_LRT_group %>% group_by(group, type, time) %>% summarise()) #作図用
`summarise()` regrouping output by 'group', 'type' (override with `.groups` argument)
#-------#

cluster_save <- kmc_LRT_group %>%
ggplot(aes(time,val,group=type,colour=type))+geom_line(aes(x=time,y=avg,colour=type),data=f_cluster)+geom_point()+facet_wrap(~cluster,2)+ggsci::scale_color_npg()+theme_minimal()+ theme(strip.text = element_text(size = 12),axis.text.x = element_text(angle = 45, hjust = 1))  + ggtitle(gggglabel)

file_path <- paste(folder_name_plot_path, "DEG_fdr0p1__", csvfilepath, "_kmeans4__cluster_type.pdf",sep="") 
ggsave(plot=cluster_save,file=file_path, width = 6, height = 6, dpi = 120)

print(cluster_save)

#-------#
cluster_save <- kmc_LRT_group %>%
ggplot(aes(time,val,group=type,colour=type))+geom_point()+facet_wrap(~cluster,2)+ggsci::scale_color_npg()+theme_minimal()+ theme(strip.text = element_text(size = 12),axis.text.x = element_text(angle = 45, hjust = 1))  + ggtitle(gggglabel)


file_path <- paste(folder_name_plot_path, "DEG_fdr0p1__", csvfilepath, "_kmeans4__cluster_type_nonline.pdf",sep="") 
ggsave(plot=cluster_save,file=file_path, width = 6, height = 6, dpi = 120)

#------------------#
#================================================#



##--------- リストを保存 -------------#
## degの情報も付け加える (20191204 ver)。

#---- LRTの情報 baseMean等を取り出す ----#
#LRT_deglist_fdr0p1 <- as_tibble(res_LRT_fdr0p1,rownames="ens_gene") %>% right_join(e2g,.) %>% filter(padj<0.1) #クラスタリングに使用
#LRT_deglist_fdr <- as_tibble(res_LRT,rownames="ens_gene") %>% filter(padj<0.1)

LRT_deglist_fdr <- LRT_deglist_fdr0p1 %>% select(-(ext_gene),-(biotype),-(chr))
print(fdr)
[1] 0.1
nrow(LRT_deglist_fdr0p1)
[1] 226
#------------------------#

arrange_rrres_LRT <- rrres_LRT %>% arrange(ens_gene)
cluster_resLRT_fdr <- full_join(arrange_rrres_LRT, LRT_deglist_fdr, by="ens_gene") %>% arrange(cluster)
nrow(cluster_resLRT_fdr)
[1] 226
file_path <- paste(folder_name_plot_path, "DEG_fdr0p1__", csvfilepath, "_kmeans4__cluster_result.csv",sep="")
readr::write_csv(cluster_resLRT_fdr,file_path)

#-- 確認 --#
arrange_rrres_LRT %>% filter(ext_gene %in% c("Myh3","Ckm","Acta1","Tnnt2","Actb","Csrp3","Tpm2","Nsdhl"))
##------------------------------------#
#20191205修正、作成

#===============================#
# mouseCTX 0438を参考に。

# strip.text.x = element_text(size=24,face="italic")
#, axis.text.x = element_text(angle = 45, hjust = 1) #X軸のラベルを傾ける場合
#, axis.text.x = element_text(hjust = 0.5) #X軸のラベルを水平にする場合

cluster_save <- kmc_LRT_group %>% ggplot(aes(time,val,group=type,colour=type))+geom_line(aes(x=time,y=avg,colour=type),data=f_clusterp)+geom_point(size=2)+facet_wrap(~cluster,1) +theme_bw() + theme(axis.text=element_text(hjust = 1, size=20), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=20),axis.title.x = element_blank(), legend.title=element_text(size=20), legend.text = element_text(size=20), strip.background = element_blank(), strip.text.x = element_text(size=24), legend.position = "top",  plot.title=element_text(size=10)) +ggsci::scale_color_npg() + ggtitle(gggglabel)

file_path <- paste(folder_name_plot_path, "DEG_fdr0p1__", csvfilepath, "_kmeans4__cluster_type__final.pdf",sep="") 
ggsave(plot=cluster_save,file=file_path, width = 12, height = 6, dpi = 120)
print(cluster_save)
#------------------#

cluster_save <- kmc_LRT_group %>% ggplot(aes(time,val,group=type,colour=type)) + geom_abline(intercept=0,slope=0,linetype="dashed",colour="gray") + geom_line(aes(x=time,y=avg,colour=type),data=f_clusterp) + geom_point(size=2)+facet_wrap(~cluster,1) +theme_bw() + theme(axis.text=element_text(hjust = 1, size=20), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=20),axis.title.x = element_blank(), legend.title=element_text(size=20), legend.text = element_text(size=20), strip.background = element_blank(), strip.text.x = element_text(size=24), legend.position = "top",  plot.title=element_text(size=10)) +ggsci::scale_color_npg() + ggtitle(gggglabel)


file_path <- paste(folder_name_plot_path, "DEG_fdr0p1__", csvfilepath, "_kmeans4__cluster_type__final_dash.pdf",sep="") 
ggsave(plot=cluster_save,file=file_path, width = 12, height = 6, dpi = 120)

print(cluster_save)

#------------------#

TPM plot

(CTX day5 DEG Up Down ver)

calculate TPM

# 2019 12月修正
# カウント0も表示するように変更 (20190722) BRB-seq_0432lane2_QC_tmpl_v6r190722_noumi_H3mm18_Dox_linear_0722 より

tpm <- umi %>% group_by(sample) %>% mutate(sample_total=sum(count),TPM=count/sum(count)*1e6) %>% ungroup
tpm_zero <- tpm %>% select(sample,ens_gene,TPM) %>% spread(sample,TPM,fill=0) %>% gather(sample, TPM, -ens_gene) #カウント0のサンプルは0を入れる 20190722追加して修正

tpm_def <- def %>% select(-count) %>% dplyr::inner_join(tpm_zero, by = "sample") #tpmをtpm_zeroに修正、20190722修正

#f <- function(x) x %>% group_by(group,type,growth,ext_gene) %>% summarise(avg=mean(TPM),se=sd(TPM)/sqrt(length(TPM))) %>% ungroup() #重要(平均を求める、geom_smooth(se=FALSE)を使わないver)

#-- 確認 --#
umi %>% group_by(sample) %>% summarise(sum(count)) # 確認
`summarise()` ungrouping output (override with `.groups` argument)
tpm_zero %>% group_by(sample) %>% summarise(sum(TPM)) # 確認
`summarise()` ungrouping output (override with `.groups` argument)
#---------#
matome <- tpm_def %>% inner_join(e2g, by = "ens_gene") #191203

readr::write_csv(matome,paste(csvfilepath, "__TPM__final191205_last200811.csv",sep="")) #191203 追加

#readr::write_csv(matome,"BRB0438noumi_190515-H3mm18KO_CTX_S2-Day0_S3_l2fc_fdr0p2ver__TPM__final191204.csv") #191203 追加

TPM fig

使用するものをプロット (191203修正)

“Acta1”,“Myh3”,“Ckm”,“Tnnt2”,“Actb”,“Csrp3”


#======== Change every data ここで順番を変更 ========#

#matome_select <- matome %>% mutate(growth=factor(growth, c("UI","Diff0h","Diff24h","Diff48h"))) %>% mutate(type=factor(type, c("Doxplus","Doxminus")))
#matome_select <- matome_select %>% mutate(time=case_when(growth=="UI" ~"UI",growth=="Diff0h"~"0h",growth=="Diff24h"~"24h",growth=="Diff48h"~"48h",TRUE~"error"))
#matome_select <- matome_select %>% mutate(time=factor(time, c("UI","0h","24h","48h")))

matome_select <- matome %>% mutate(time=factor(time, c("UI", "0h","24h","48h"))) %>% mutate(type=factor(type,c("DoxPlus","DoxMinus"))) %>% mutate(rep=factor(rep, c("1", "2", "3", "4")))


#matome_select <- matome %>% filter(intact_CTX=="CTX"|intact_CTX=="SKM") %>%  mutate(WT_KO=factor(WT_KO, c("H3mm18KO","WT"))) %>% mutate(Day=factor(Day, c("Day0","Day5","Day14"))) %>% mutate(intact_CTX=factor(intact_CTX, c("CTX","SKM")))

#-------#

tbl <- matome_select %>% filter(ext_gene %in% c("Myh3","Ckm","Acta1","Tnnt2","Actb","Csrp3"))

#tbl2 <- matome_select %>% filter(ext_gene %in% c("Acta1","Tpm2"))

#====================================================#

#f <- function(x) x %>% group_by(WT_KO,Day,intact_CTX,ext_gene) %>% summarise(avg=mean(TPM),se=sd(TPM)/sqrt(length(TPM))) %>% ungroup() #重要 (CTX用に変更)

f <- function(x) x %>% group_by(group, type, time, ext_gene) %>% summarise(avg=mean(TPM),se=sd(TPM)/sqrt(length(TPM))) %>% ungroup()
#----#
tbl %>% group_by(group, type, time) %>% summarize()
`summarise()` regrouping output by 'group', 'type' (override with `.groups` argument)
#----#

#face="italic"
#, axis.text.x = element_text(angle = 45, hjust = 1) #X軸のラベルを傾ける場合
#, axis.text.x = element_text(hjust = 0.5) #X軸のラベルを水平にする場合

### point ###
gggggpp <-  ggplot(tbl,aes(time,TPM,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",2)+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=20,face="italic"), legend.position = "top",  plot.title=element_text(size=16))+ggsci::scale_color_npg()


file_path <- paste("TPM__", csvfilepath, "__with_point__final191205_last200811.pdf",sep="")
ggsave(file=file_path, plot = gggggpp, dpi = 100, width = 12, height = 10)

#ggsave(file=file_path, plot = gggggpp)
#ggsave(file="TPM__BRB0438noumi_H3mm18KO_CTX_S2-Day0_S3__with_point__final191204.pdf", plot = gggggpp)
print(gggggpp)

gggggpp <-  ggplot(tbl,aes(time,TPM,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",2)+geom_smooth(se=FALSE)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=20,face="italic"), legend.position = "top",  plot.title=element_text(size=16))+ggsci::scale_color_npg()

file_path <- paste("TPM__", csvfilepath, "__with_point__final191205_last200811_smooth.pdf",sep="")
ggsave(file=file_path, plot = gggggpp, dpi = 100, width = 12, height = 10)


#ggsave(file=file_path, plot = gggggpp)
#ggsave(file="TPM__BRB0438noumi_H3mm18KO_CTX_S2-Day0_S3__with_point__final191204_smooth.pdf", plot = gggggpp)
#print(gggggpp)

“Acta1”,“Myh3”,“Nsdhl”

#20191204 作成

tbl2 <- matome_select %>% filter(ext_gene %in% c("Acta1","Myh3","Nsdhl"))
#%>% mutate(ext_gene=factor(ext_gene, c("Acta1","Nsdhl","Myh3")))

#===============================#
## SKMもCTXと同じ色で表示

### point ###
gggggpp <-  ggplot(tbl2,aes(time,TPM,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y")+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=20), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=20),axis.title.x = element_blank(), legend.title=element_text(size=20), legend.text = element_text(size=20), strip.background = element_blank(), strip.text.x = element_text(size=24,face="italic"), legend.position = "top",  plot.title=element_text(size=20)) +ggsci::scale_color_npg()  + ggtitle("3T3 Dox +-")

file_path <- paste("TPM__", csvfilepath, "__with_point__Acta1_Myh3_Nsdhl__final191205_last200811.pdf",sep="")
ggsave(file=file_path, plot = gggggpp, dpi = 100, width = 12, height = 6) #2つ図なら width = 8
print(gggggpp)


#ggsave(file=file_path, plot = gggggpp, dpi = 100, width = 8, height = 6) #2つ図なら width = 8
#ggsave(file="TPM__BRB0438noumi_H3mm18KO_CTX_S2-Day0_S3__with_point__Acta1_Tpm2__final191204.pdf", plot = gggggpp, dpi = 100, width = 8, height = 6)

“Slc38a2”,“Inhba”,“Acta1”,“Myog”,“Myh9”,“Rpl13”

#20191204 作成

rrres_LRT %>% filter(ext_gene %in% c("Slc38a2","Inhba","Acta1","Myog","Myh9","Rpl13"))

nbl3 <- matome_select %>% filter(ext_gene %in% c("Slc38a2","Inhba","Acta1","Myog","Myh9","Rpl13"))  %>% mutate(ext_gene=factor(ext_gene,c("Slc38a2","Inhba","Acta1","Myog","Myh9","Rpl13"))) 


#===============================#
## SKMもCTXと同じ色で表示

### point ###
gggggpp <-  ggplot(nbl3,aes(time,TPM,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y")+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=20), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=20),axis.title.x = element_blank(), legend.title=element_text(size=20), legend.text = element_text(size=20), strip.background = element_blank(), strip.text.x = element_text(size=24,face="italic"), legend.position = "top",  plot.title=element_text(size=20)) +ggsci::scale_color_npg()  + ggtitle("3T3 Dox +-")

file_path <- paste("TPM__", csvfilepath, "__with_point__Cluste_Rep__final191205_last200811.pdf",sep="")
ggsave(file=file_path, plot = gggggpp, dpi = 100, width = 12, height = 6) #2つ図なら width = 8
print(gggggpp)


#ggsave(file=file_path, plot = gggggpp, dpi = 100, width = 8, height = 6) #2つ図なら width = 8
#ggsave(file="TPM__BRB0438noumi_H3mm18KO_CTX_S2-Day0_S3__with_point__Acta1_Tpm2__final191204.pdf", plot = gggggpp, dpi = 100, width = 8, height = 6)

ALL DEG, LRT FDR < 0.1

# DEGをclusterに分けて表示 (191206作成)

#-- 設定 -----#
plot_title1 <- "TPM"
plot_title2 <- "DEG (LRT): BRB-seq 3T3 Dox +-"
#folder_name <- "LRT"

#-- ファイル名 の設定 ---#
plot_title0 <- paste(plot_title1, plot_title2, sep=", ")
#folder_name_plot0 <- paste(".",folder_name, plot_title1,"",sep="/")
#folder_name_plot_path <- paste(folder_name_plot0,paste(folder_name,plot_title1,"",sep="_"),sep="")

#------------------------#

#===============================#

#----- 上で出てきたDEGのリストの取り出し -----#
deg_cluster_list <- rrres_LRT  %>% arrange(cluster)
deg_cluster_size <- deg_cluster_list %>% arrange(ens_gene) %>% group_by(cluster) %>% summarize(size=n())
`summarise()` ungrouping output (override with `.groups` argument)
#----- DEGのみ取り出す ------#
deg_matome <- matome %>% filter(ens_gene %in% deg_cluster_list$ens_gene) %>% right_join(deg_cluster_list %>% select(ens_gene,cluster), by = "ens_gene")
#deg_matome <- deg_matome %>% mutate(growth=factor(growth, c("UI","Diff0h","Diff24h","Diff48h"))) %>% mutate(type=factor(type, c("Doxplus","Doxminus")))
#deg_matome <- deg_matome %>% mutate(time=case_when(growth=="UI" ~"UI",growth=="Diff0h"~"0h",growth=="Diff24h"~"24h",growth=="Diff48h"~"48h",TRUE~"error"))
#deg_matome <- deg_matome %>% mutate(time=factor(time, c("UI","0h","24h","48h")))


deg_matome <- deg_matome %>% mutate(time=factor(time, c("UI", "0h","24h","48h"))) %>% mutate(type=factor(type,c("DoxPlus","DoxMinus"))) %>% mutate(rep=factor(rep, c("1", "2", "3", "4")))


#------------------------------#

f <- function(x) x %>% group_by(group, type, time, ext_gene) %>% summarise(avg=mean(TPM),se=sd(TPM)/sqrt(length(TPM))) %>% ungroup()

#===============================#
### point ###
## クラスターごと ##
for (i in 1:4) {
  cluster_now <- paste("cluster",deg_cluster_size$cluster[i],sep="")
  plot_title0_cluster <- paste(plot_title0, cluster_now, deg_cluster_size$size[i], sep=", ") #クラスターの個数も表示(20191025)
  
  print(plot_title0_cluster)
  
  ppplotsize <- (as.integer(deg_cluster_size$size[i]/10) + 1) * 2 + 1
  
  cluster_plotsave <- deg_matome %>% filter(cluster==deg_cluster_size$cluster[i]) %>%  ggplot(aes(time,TPM,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",ncol=10)+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(angle = 45, hjust = 1), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=18,face="italic"), legend.position = "top",  plot.title=element_text(size=16)) +ggsci::scale_color_npg() + ggtitle(plot_title0_cluster)
  
  
  file_path <- paste(folder_name_plot_path, "TPM__", csvfilepath, "__LRTDEG_fdr0p1__final191205_last200811_",cluster_now,".pdf",sep="") 
  ggsave(plot=cluster_plotsave,file=file_path, width = 20, height = ppplotsize, dpi = 120, limitsize = FALSE)

}
[1] "TPM, DEG (LRT): BRB-seq 3T3 Dox +-, cluster1, 42"
[1] "TPM, DEG (LRT): BRB-seq 3T3 Dox +-, cluster2, 54"
[1] "TPM, DEG (LRT): BRB-seq 3T3 Dox +-, cluster3, 93"
[1] "TPM, DEG (LRT): BRB-seq 3T3 Dox +-, cluster4, 37"
#===============================#
### point ###
## まとめて ##

#-- 斜めのラベル --#

ppplotsize <- (as.integer(nrow(deg_cluster_list)/10) + 1) * 2 + 1

cluster_plotsave <- deg_matome %>% ggplot(aes(time,TPM,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",ncol=10)+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(angle = 45, hjust = 1), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=18,face="italic"), legend.position = "top",  plot.title=element_text(size=16)) +ggsci::scale_color_npg() + ggtitle("3T3 Dox +-")


file_path <- paste(folder_name_plot_path, "TPM__", csvfilepath, "__LRTDEG_fdr0p1__final191205_last200811_all_1.pdf",sep="") 
ggsave(plot=cluster_plotsave,file=file_path, width = 20, height = ppplotsize, dpi = 360, limitsize = FALSE)

#-- 横向きのラベル --#

ppplotsize <- ppplotsize * 1.25

cluster_plotsave <- deg_matome %>% ggplot(aes(time,TPM,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",ncol=10)+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=18,face="italic"), legend.position = "top",  plot.title=element_text(size=16)) +ggsci::scale_color_npg() + ggtitle("3T3 Dox +-")

file_path <- paste(folder_name_plot_path, "TPM__", csvfilepath, "__LRTDEG_fdr0p1__final191205_last200811_all_2.pdf",sep="") 
ggsave(plot=cluster_plotsave,file=file_path, width = 25, height = ppplotsize, dpi = 360, limitsize = FALSE)


#--memo--#
#face="italic"
#, axis.text.x = element_text(angle = 45, hjust = 1) #X軸のラベルを傾ける場合
#, axis.text.x = element_text(hjust = 0.5) #X軸のラベルを水平にする場合

TPM作図終了

normalizedcount plot

set normCount table

# 2019 12月作成

nrow(normalizedcount)
[1] 21707
nrow(normalizedcount %>% inner_join(e2g, by = "ens_gene"))
[1] 21707
#---------#
norm_plotlist_all <- normalizedcount %>% gather("sample", "normalized",-(ens_gene)) %>% inner_join(def, by = "sample") %>% inner_join(e2g, by = "ens_gene") 
#norm_plotlist_all <- norm_plotlist_all %>% mutate(growth=factor(growth, c("UI","Diff0h","Diff24h","Diff48h"))) %>% mutate(type=factor(type, c("Doxplus","Doxminus")))
#norm_plotlist_all <- norm_plotlist_all %>% mutate(time=case_when(growth=="UI" ~"UI",growth=="Diff0h"~"0h",growth=="Diff24h"~"24h",growth=="Diff48h"~"48h",TRUE~"error"))
#norm_plotlist_all <- norm_plotlist_all %>% mutate(time=factor(time, c("UI","0h","24h","48h")))

norm_plotlist_all <- norm_plotlist_all %>% mutate(time=factor(time, c("UI", "0h","24h","48h"))) %>% mutate(type=factor(type,c("DoxPlus","DoxMinus"))) %>% mutate(rep=factor(rep, c("1", "2", "3", "4")))

readr::write_csv(norm_plotlist_all,paste(csvfilepath, "__normCount__final191205_last200811.csv",sep="")) #191206 追加

normcount fig

ALL DEG, LRT FDR < 0.1 (Total 229)

# 20191205修正、20191024
# DEGをclusterに分けて表示 (191206作成)

#-- 設定 -----#
plot_title1 <- "normCount"
plot_title2 <- "DEG (LRT): BRB-seq 3T3 Dox +-"
#folder_name <- "LRT"

#-- ファイル名 の設定 ---#
plot_title0 <- paste(plot_title1, plot_title2, sep=", ")
#folder_name_plot0 <- paste(".",folder_name, plot_title1,"",sep="/")
#folder_name_plot_path <- paste(folder_name_plot0,paste(folder_name,plot_title1,"",sep="_"),sep="")

#------------------------#

#===============================#
## norm count 後のデータ

#----- 上で出てきたDEGのリストの取り出し -----#
#----- DEGのみ取り出す ------#
deg_normcount <- norm_plotlist_all %>% filter(ens_gene %in% deg_cluster_list$ens_gene) %>% right_join(deg_cluster_list %>% select(ens_gene,cluster), by = "ens_gene")
#deg_normcount <- deg_normcount %>% mutate(growth=factor(growth, c("UI","Diff0h","Diff24h","Diff48h"))) %>% mutate(type=factor(type, c("Doxplus","Doxminus")))
#deg_normcount <- deg_normcount %>% mutate(time=case_when(growth=="UI" ~"UI",growth=="Diff0h"~"0h",growth=="Diff24h"~"24h",growth=="Diff48h"~"48h",TRUE~"error"))
#deg_normcount <- deg_normcount %>% mutate(time=factor(time, c("UI","0h","24h","48h")))

#plotlist_cluster <- deg_normcount
#------------------------------#


f_gene_norm <- function(x) x %>% group_by(group, type, time, ext_gene) %>% summarise(avg=mean(normalized),se=sd(normalized)/sqrt(length(normalized))) %>% ungroup()
#f <- function(x) x %>% group_by(group, type, time, ext_gene) %>% summarise(avg=mean(TPM),se=sd(TPM)/sqrt(length(TPM))) %>% ungroup()

#===============================#
### point ###
## クラスターごと ##
for (i in 1:4) {
  cluster_now <- paste("cluster",deg_cluster_size$cluster[i],sep="")
  plot_title0_cluster <- paste(plot_title0, cluster_now, deg_cluster_size$size[i], sep=", ") #クラスターの個数も表示(20191025)
  
  print(plot_title0_cluster)
  
  ppplotsize <- (as.integer(deg_cluster_size$size[i]/10) + 1) * 2 + 1
  
  cluster_plotsave <- deg_normcount %>% filter(cluster==deg_cluster_size$cluster[i]) %>%  ggplot(aes(time,normalized,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",ncol=10)+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f_gene_norm)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(angle = 45, hjust = 1), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=18,face="italic"), legend.position = "top",  plot.title=element_text(size=16)) +ggsci::scale_color_npg() + ggtitle(plot_title0_cluster) + ylab("normalized count") 
  
  
  file_path <- paste(folder_name_plot_path, "normCount__", csvfilepath, "__LRTDEG_fdr0p1__final191205_last200811_",cluster_now,".pdf",sep="") 
  ggsave(plot=cluster_plotsave,file=file_path, width = 20, height = ppplotsize, dpi = 120, limitsize = FALSE)

}
[1] "normCount, DEG (LRT): BRB-seq 3T3 Dox +-, cluster1, 42"
[1] "normCount, DEG (LRT): BRB-seq 3T3 Dox +-, cluster2, 54"
[1] "normCount, DEG (LRT): BRB-seq 3T3 Dox +-, cluster3, 93"
[1] "normCount, DEG (LRT): BRB-seq 3T3 Dox +-, cluster4, 37"
#===============================#
### point ###
## まとめて ##

#-- 斜めのラベル --#

ppplotsize <- (as.integer(nrow(deg_cluster_list)/10) + 1) * 2 + 1

cluster_plotsave <- deg_normcount %>% ggplot(aes(time,normalized,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",ncol=10)+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f_gene_norm)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(angle = 45, hjust = 1), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=18,face="italic"), legend.position = "top",  plot.title=element_text(size=16)) +ggsci::scale_color_npg() + ggtitle("3T3 Dox +-") + ylab("normalized count") 


file_path <- paste(folder_name_plot_path, "normCount__", csvfilepath, "__LRTDEG_fdr0p1__final191205_last200811_all_1.pdf",sep="") 
ggsave(plot=cluster_plotsave,file=file_path, width = 20, height = ppplotsize, dpi = 360, limitsize = FALSE)

#-- 横向きのラベル --#

ppplotsize <- ppplotsize * 1.25

cluster_plotsave <- deg_normcount %>% ggplot(aes(time,normalized,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",ncol=10)+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f_gene_norm)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=18,face="italic"), legend.position = "top",  plot.title=element_text(size=16)) +ggsci::scale_color_npg() + ggtitle("3T3 Dox +-") + ylab("normalized count") 

file_path <- paste(folder_name_plot_path, "normCount__", csvfilepath, "__LRTDEG_fdr0p1__final191205_last200811_all_2.pdf",sep="") 
ggsave(plot=cluster_plotsave,file=file_path, width = 25, height = ppplotsize, dpi = 360, limitsize = FALSE)


#--memo--#
#face="italic"
#, axis.text.x = element_text(angle = 45, hjust = 1) #X軸のラベルを傾ける場合
#, axis.text.x = element_text(hjust = 0.5) #X軸のラベルを水平にする場合

使用するものをプロット

“Acta1”,“Myh3”,“Ckm”,“Tnnt2”,“Actb”,“Csrp3”


#======== Change every data ここで順番を変更 ========#

#-------#

nbl <- norm_plotlist_all %>% filter(ext_gene %in% c("Myh3","Ckm","Acta1","Tnnt2","Actb","Csrp3"))

#====================================================#

#f_gene_norm <- function(x) x %>% group_by(group, type, time, ext_gene) %>% summarise(avg=mean(normalized),se=sd(normalized)/sqrt(length(normalized))) %>% ungroup()

#----#
nbl %>% group_by(group, type, time) %>% summarize()
`summarise()` regrouping output by 'group', 'type' (override with `.groups` argument)
#----#

#face="italic"
#, axis.text.x = element_text(angle = 45, hjust = 1) #X軸のラベルを傾ける場合
#, axis.text.x = element_text(hjust = 0.5) #X軸のラベルを水平にする場合

### point ###
gggggpp <-  ggplot(nbl,aes(time,normalized,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",2)+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f_gene_norm)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=20,face="italic"), legend.position = "top",  plot.title=element_text(size=16))+ggsci::scale_color_npg()  + ylab("normalized count")

file_path <- paste("normCount__", csvfilepath, "__with_point__final191205_last200811.pdf",sep="")
ggsave(file=file_path, plot = gggggpp, dpi = 100, width = 12, height = 10)

print(gggggpp)


gggggpp <-  ggplot(nbl,aes(time,normalized,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",2)+geom_smooth(se=FALSE)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=16), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=16),axis.title.x = element_blank(), legend.title=element_text(size=16), legend.text = element_text(size=16), strip.background = element_blank(), strip.text.x = element_text(size=20,face="italic"), legend.position = "top",  plot.title=element_text(size=16))+ggsci::scale_color_npg()  + ylab("normalized count")

file_path <- paste("normCount__", csvfilepath, "__with_point__final191205_last200811_smooth.pdf",sep="")
ggsave(file=file_path, plot = gggggpp, dpi = 100, width = 12, height = 10)

NA
NA

“Acta1”,“Myh3”,“Nsdhl”

#20191204 作成

nbl2 <- norm_plotlist_all %>% filter(ext_gene %in% c("Acta1","Myh3","Nsdhl"))

#%>% mutate(ext_gene=factor(ext_gene, c("Acta1","Nsdhl","Myh3")))

#===============================#

### point ###
gggggpp <-  ggplot(nbl2,aes(time,normalized,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y")+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f_gene_norm)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=20), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=20),axis.title.x = element_blank(), legend.title=element_text(size=20), legend.text = element_text(size=20), strip.background = element_blank(), strip.text.x = element_text(size=24,face="italic"), legend.position = "top",  plot.title=element_text(size=20)) +ggsci::scale_color_npg()  + ggtitle("3T3 Dox +-")  + ylab("normalized count")

file_path <- paste("normCount__", csvfilepath, "__with_point__Acta1_Myh3_Nsdhl__final191205_last200811.pdf",sep="")
ggsave(file=file_path, plot = gggggpp, dpi = 100, width = 12, height = 6) #2つ図なら width = 8
print(gggggpp)

NA
NA
#20191204 作成

rrres_LRT %>% filter(ext_gene %in% c("Slc38a2","Inhba","Acta1","Myog","Myh9","Rpl13"))

nbl3 <- norm_plotlist_all %>% filter(ext_gene %in% c("Slc38a2","Inhba","Acta1","Myog","Myh9","Rpl13"))  %>% mutate(ext_gene=factor(ext_gene,c("Slc38a2","Inhba","Acta1","Myog","Myh9","Rpl13"))) 

#%>% mutate(ext_gene=factor(ext_gene, c("Acta1","Nsdhl","Myh3")))

#===============================#

### point ###
gggggpp <-  ggplot(nbl3,aes(time,normalized,group=type,colour=type))+geom_point(size=2)+facet_wrap(~ext_gene,scale="free_y",nrow=1)+geom_line(size=1.0, aes(x=time,y=avg,colour=type),data=f_gene_norm)+theme_bw() + ylim(0,NA) + theme(axis.text=element_text(hjust = 1, size=20), axis.text.x = element_text(hjust = 0.5), axis.title=element_text(size=20),axis.title.x = element_blank(), legend.title=element_text(size=20), legend.text = element_text(size=20), strip.background = element_blank(), strip.text.x = element_text(size=24,face="italic"), legend.position = "top",  plot.title=element_text(size=20)) +ggsci::scale_color_npg()  + ggtitle("3T3 Dox +-")  + ylab("normalized count")

file_path <- paste("normCount__", csvfilepath, "__with_point__Cluste_Rep__final191205_last200811.pdf",sep="")
ggsave(file=file_path, plot = gggggpp, dpi = 100, width = 16, height = 5) #2つ図なら width = 8
print(gggggpp)


nbl3

ここまで実行

GO解析

クラスタリング の結果をGO

20191206修正

#20191206修正

file_path <- paste(folder_name_plot_path, "DEG_fdr0p1__", csvfilepath, "_kmeans4__kmeans_cluster.csv",sep="") 
print(file_path)
[1] "./LRT/DEG_fdr0p1__BRB0432lane2noumi_H3mm18_Dox_kmeans4__kmeans_cluster.csv"
file_degcluster <- file_path

table_degcluster <- readr::read_csv(file_degcluster) %>% arrange(ens_gene) %>% dplyr::select(ens_gene,ext_gene,cluster)
Parsed with column specification:
cols(
  ens_gene = col_character(),
  ext_gene = col_character(),
  biotype = col_character(),
  chr = col_character(),
  cluster = col_double()
)
table_degcluster %>% group_by(cluster) %>% summarise(size=n())
`summarise()` ungrouping output (override with `.groups` argument)
##### FDR setting ######
gofdr <- 0.1

cluster_num <- 4
# 20191206修正

library(clusterProfiler)
library(org.Mm.eg.db)

folder_path <- "./LRT/clusterProfile/"

#-------------#
file_path <- paste(folder_path, "DEG_fdr0p1__", csvfilepath, "_kmeans_BPfdr0p1_generatio",sep="")
filename_csv <- file_path

file_path <- paste(folder_path, "DEG_fdr0p1__", csvfilepath, "_kmeans_BPfdr0p1_generatio_cluster",sep="")
filename_list <- file_path

print(filename_list)
[1] "./LRT/clusterProfile/DEG_fdr0p1__BRB0432lane2noumi_H3mm18_Dox_kmeans_BPfdr0p1_generatio_cluster"
print(filename_csv)
[1] "./LRT/clusterProfile/DEG_fdr0p1__BRB0432lane2noumi_H3mm18_Dox_kmeans_BPfdr0p1_generatio"
#例 filename_list <- "./LRT/clusterProfile/H3mm18KO_mouseCTX_BRB0438_day5_2gunfdr0p2_kmeans_BPfdr0p1_generatio_cluster"
#例 filename_csv <- "./LRT/clusterProfile/H3mm18KO_mouseCTX_BRB0438_day5_2gunfdr0p2_kemans_BPfdr0p1_generatio"
#-------------#

cluster_list <- as.list(NA) #初期化

for (i in 1:cluster_num) {
   pre_list <- as.list(NA)
   pre_list <- table_degcluster %>% filter(cluster==as.double(i)) %>% dplyr::select(ens_gene) %>% as.list()
   names(pre_list) <- paste("ENSEMBL",as.character(i),sep="_")
 
   if (i == 1) { 
     cluster_list <- pre_list
   } 
   else cluster_list <- c(cluster_list, pre_list) 
}


for (i in 1:cluster_num) {
   print(paste(i, cluster_list[[i]] %>% tibble::enframe(name = NULL) %>% nrow(), sep=", "))
  
   pre_ego_BP <- enrichGO(gene = cluster_list[[i]],
                 OrgDb = "org.Mm.eg.db",
                 keyType = 'ENSEMBL',
                 ont = "BP",
                 pAdjustMethod = "BH",
                 pvalueCutoff  = gofdr, qvalueCutoff  = 1.0) #20191211修正  pvalueCutoff  = fdr
   
   ## pvalue < qvalue < p.adjust ##
   # qvalueCutoff  = 0.3  qvalueCutoff  = 0.2 , qvalueCutoff  = 1.0

  
   if (i == 1) { 
     table_ego_BP <- data.frame(pre_ego_BP) %>% mutate(cluster=paste("cluster",as.character(i),sep=""))  # リスト型からデータフレームへ変換
   } 
   else table_ego_BP <- table_ego_BP %>% bind_rows(data.frame(pre_ego_BP) %>% mutate(cluster=paste("cluster",as.character(i),sep="")))
   
   #---- plot ---#
   BPplot <- dotplot(pre_ego_BP, showCategory=30, orderBy = "Count") #clusterProfile の機能で図を描く(191106修正) wrong orderBy parameter; set to default `orderBy = "x"`
   print(BPplot)
   ggsave(BPplot,file=paste(filename_list,as.character(i),".png",sep=""), width = 8, height = 12, dpi = 120)
   
   BPplot <- dotplot(pre_ego_BP, showCategory=10, orderBy = "Count") #clusterProfile の機能で図を描く(191106修正) wrong orderBy parameter; set to default `orderBy = "x"`
   print(BPplot)
   ggsave(BPplot,file=paste(filename_list,as.character(i),"_Category10.png",sep=""), width = 8, height = 4, dpi = 120)
   
   BPplot <- dotplot(pre_ego_BP, showCategory=5, orderBy = "Count") #clusterProfile の機能で図を描く(191106修正) wrong orderBy parameter; set to default `orderBy = "x"`
   print(BPplot)
   ggsave(BPplot,file=paste(filename_list,as.character(i),"_Category5.png",sep=""), width = 8, height = 3, dpi = 120)
}
[1] "1, 42"
[1] "2, 54"
[1] "3, 93"
[1] "4, 37"

print(table_ego_BP %>% group_by(cluster) %>% summarize())
`summarise()` ungrouping output (override with `.groups` argument)
#------#
# データはtable_ego_BPに。
# 20191206修正
#------------------------------------------------------#
# テーブルを保存
# table_ego_BP_3t3_LRT2 <- table_ego_BP

table_ego_BP1 <- table_ego_BP %>% mutate(cluster=factor(cluster,c("cluster1","cluster2","cluster3","cluster4"))) %>% arrange(cluster,desc(Count)) #191106

readr::write_csv(table_ego_BP1,paste(filename_csv,".csv",sep=""))

# 先のテーブルのgeneIDをgene nameに置換する。(20191025)

tablego <- table_ego_BP1 %>% mutate(gene_name=geneID) %>% dplyr::select(-(qvalue))

for (i in 1:nrow(table_degcluster)) {
  tablego <- tablego %>% mutate(gene_name=gsub(gene_name, pattern=table_degcluster$ens_gene[i], replacement=table_degcluster$ext_gene[i], ignore.case = TRUE))
}

print(tablego)

readr::write_csv(tablego,paste(filename_csv,"_genename.csv",sep=""))

#------------------------------------------------------#

#GOのtermの数
print(tablego %>% group_by(cluster) %>% summarize(cluster_3t3Dox_num = dplyr::n()))
`summarise()` ungrouping output (override with `.groups` argument)
## 変更 ##
table_ego_BP_2gunfdr0p2_cluster <- tablego

#--- メモ ----#
#tableggg <- table_ego_clustercluster
#colm <- tableggg$geneID
#for (i in 1:88) {
#  colm <- sub(rrres_cluster3$ens_gene[i], rrres_cluster3$ext_gene[i], colm)
#}
#print(colm)
# 20191206, 191211修正
# Benjamini correction を p-adjust として使用する

file_path <- paste(folder_path, "DEG_fdr0p1__", csvfilepath, "_kmeans_BPfdr0p1.pdf",sep="")
file_BP_plot <- file_path

file_path <- paste(folder_path, "DEG_fdr0p1__", csvfilepath, "_kmeans__BPfdr0p1_muscleonly.pdf",sep="")
file_BP_plot_muscle <- file_path

print(file_BP_plot)
[1] "./LRT/clusterProfile/DEG_fdr0p1__BRB0432lane2noumi_H3mm18_Dox_kmeans_BPfdr0p1.pdf"
print(file_BP_plot_muscle)
[1] "./LRT/clusterProfile/DEG_fdr0p1__BRB0432lane2noumi_H3mm18_Dox_kmeans__BPfdr0p1_muscleonly.pdf"
# 例 file_BP_plot <- "./2gun/clusterProfile/BPfdr0p1__H3mm18KO_mouseCTX_BRB0438_day5_2gunfdr0p2_kmeans.pdf"
# 例 file_BP_plot_muscle <- "./2gun/clusterProfile/BPfdr0p1__H3mm18KO_mouseCTX_BRB0438_day5_2gunfdr0p2_kmeans_muscleonly.pdf"

#--------------------#

BP_matome <- tablego

rowlength <- BP_matome %>% group_by(Description) %>% summarize() %>% nrow()
`summarise()` ungrouping output (override with `.groups` argument)
BP_plot <- BP_matome %>% filter(p.adjust<gofdr) %>% ggplot(aes(x=cluster, y=reorder(Description,Count), size=Count, fill=p.adjust)) + geom_point(shape = 21) + theme(strip.text = element_text(size = 10)) + theme_minimal() + theme(strip.text = element_text(size = 12),axis.text.x = element_text(angle = 45, hjust = 1)) + scale_fill_gradient(low = "red" , high = "blue")+ xlab("3T3 Dox +-") + ylab("GO Description (BP)") + labs(fill=paste("p.adjust (BH) < ",as.character(gofdr),sep=""))
print(BP_plot)
ggsave(plot=BP_plot,file=file_BP_plot, width = 10, height = (5+rowlength/6), dpi = 120,limitsize = FALSE)


#---muscle関連のみ
BP_matome_muscle <- BP_matome %>% filter(grepl("muscle", Description)|grepl("myo", Description))
rowlength <- BP_matome_muscle %>% group_by(Description) %>% summarize() %>% nrow()
`summarise()` ungrouping output (override with `.groups` argument)
BP_plot_muscle <- BP_matome_muscle %>% filter(p.adjust<gofdr) %>% ggplot(aes(x=cluster, y=reorder(Description,Count), size=Count, fill=p.adjust)) + geom_point(shape = 21) + theme(strip.text = element_text(size = 10)) + theme_minimal() + theme(strip.text = element_text(size = 12),axis.text.x = element_text(angle = 45, hjust = 1)) + scale_fill_gradient(low = "red" , high = "blue") + xlab("3T3 Dox +- (muscle)") + ylab("GO Description (BP)") + labs(fill=paste("p.adjust (BH) < ",as.character(gofdr),sep=""))
print(BP_plot_muscle)
ggsave(BP_plot_muscle,file=file_BP_plot_muscle, width = 8, height = (5+rowlength/6), dpi = 120,limitsize = FALSE)

NA
NA
# 20191206修正
# 20191003追加, 191120変更

#----- countのみのtable --------------#
aaa_tablego <- tablego %>% dplyr::select(ID,Description,cluster,Count) %>% spread(key=cluster,value = Count,fill=0) %>% mutate(Total= cluster2 + cluster3 +cluster4)  %>% arrange(desc(Total))

#aaa_tablego <- tablego %>% dplyr::select(ID,Description,cluster,Count) %>% spread(key=cluster,value = Count,fill=0) %>% mutate(Total= cluster1 +cluster2 + cluster3 +cluster4)  %>% arrange(desc(Total))

file_path <- paste(folder_path, "DEG_fdr0p1__", csvfilepath, "_kmeans__BPfdr0p1__count_table.csv",sep="")
print(file_path)
[1] "./LRT/clusterProfile/DEG_fdr0p1__BRB0432lane2noumi_H3mm18_Dox_kmeans__BPfdr0p1__count_table.csv"
readr::write_csv(aaa_tablego,file_path)

#例 "./2gun/clusterProfile/BPfdr0p1__H3mmKO_mouseCTX_BRB0438_2gunfdr0p2_kemans__count_table.csv"
#-------------------------------------#
# x=pvalue, y=p.adjust
plottt <- table_ego_BP %>% ggplot(aes(x=pvalue, y=p.adjust, size=Count)) + geom_point()+geom_abline(intercept=0,slope=1.0,linetype="dashed",colour="blue") + xlim(0,NA) + ylim(0,NA) + ggtitle(label=paste("p.adjust (BH) < ",as.character(gofdr),sep=""))
print(plottt)


# x=pvalue, y=qvalue
plottt <- table_ego_BP %>% ggplot(aes(x=pvalue, y=qvalue, size=Count)) + geom_point()+geom_abline(intercept=0,slope=1.0,linetype="dashed",colour="blue") + xlim(0,NA) + ylim(0,NA) + ggtitle(label=paste("p.adjust (BH) < ",as.character(gofdr),sep=""))
print(plottt)


# x=p.adjust, y=qvalue
plottt <- table_ego_BP %>% ggplot(aes(x=p.adjust, y=qvalue, size=Count)) + geom_point()+geom_abline(intercept=0,slope=1.0,linetype="dashed",colour="blue") + xlim(0,NA) + ylim(0,NA) + ggtitle(label=paste("p.adjust (BH) < ",as.character(gofdr),sep=""))
print(plottt)



## pvalue < qvalue < p.adjust ##
# pvalue < p.adjust
# pvalue < qvalue
# qvalue < p.adjust

#---------------------#

#[BBRB-seq_0438_QC_tmpl_v6_noumi_190515-H3mm18KO_CTX_S2-Day0_S3_fdr0p2ver_and_LRT_191024  (umi補正なし,fdr0.2) (TPM 190722ver) (190924を元に) (190627-1024)]を参考にした。

#pvalueCutoff   
#pvalue cutoff on enrichment tests to report

#pAdjustMethod  
#one of "holm", "hochberg", "hommel", "bonferroni", "BH", "BY", "fdr", "none"

#qvalueCutoff   
#qvalue cutoff on enrichment tests to report as significant. Tests must pass i) pvalueCutoff on unadjusted pvalues, ii) pvalueCutoff on adjusted pvalues and iii) qvalueCutoff on qvalues to be reported.

# 設定(pvalueCutoff  = 0.1, qvalueCutoff  = 0.2)だと、p値<0.1, p.adjust値<0.1, q値<0.2 になっている。

GOここまで

この後に以前はfantom5のデータのコードが入っていたが、カット。 mouse CTX (BRB 0438) の結果との比較もカット

LS0tCnRpdGxlOiAiW0xhc3QgMjAwODExLCBGaW5hbCAxOTEyMDUtMTIxMiwgMThwcm9qZWN0LCAzVDNdIEJSQnNlcTA0MzJsYW5lMl9RQ190bXBsX3Y2X25vdW1pX0gzbW0xOF9Eb3hfbGluZWFyXzA3MThfZmluMTkxMjA1X2xhc3QyMDA4MTEgKHVtaeijnOato+OBquOBlyxmZHIwLjEpIChUUE0s5bCk5bqm5q+U5qSc5a6aKSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IAogICAgdG9jOiB5ZXMKICBwZGZfZG9jdW1lbnQ6IAogICAga2VlcF90ZXg6IHllcwogICAgbGF0ZXhfZW5naW5lOiBsdWFsYXRleAotLS0KCiMjIyBTZXR1cAoKYGBge3IgbGlicmFyaWVzLG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShwdXJycikKc291cmNlKCIvaG9tZS9ndWVzdEEvbjcwMjc1Yi93b3JrL3JzY3JpcHRzL2dlb21Ob3JtLlIiKQoKIyBIZWxwZXIgZnVuY3Rpb24KI2dncG9pbnRzIDwtIGZ1bmN0aW9uKHgsLi4uKSAKIyAgZ2dwbG90KHgsLi4uKSArIGdlb21fcG9pbnQoc2l6ZT0zLHN0cm9rZT0xKSArCiMgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChzaXplPTQpICsgdGhlbWVfbWluaW1hbCgpICsgbXljb2xvcgoKIyMg44Op44OZ44Or44GC44KKCmdncG9pbnRzIDwtIGZ1bmN0aW9uKHgsLi4uKSAKICBnZ3Bsb3QoeCwuLi4pICsgZ2VvbV9wb2ludChzdHJva2U9MSkgKwogIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChzaXplPTQpICsgdGhlbWVfbWluaW1hbCgpICsgbXljb2xvcgoKIyMg44Op44OZ44Or44Gq44GXCiNnZ3BvaW50cyA8LSBmdW5jdGlvbih4LC4uLikgCiMgIGdncGxvdCh4LC4uLikgKyBnZW9tX3BvaW50KHN0cm9rZT0xKSArIHRoZW1lX21pbmltYWwoKSArIG15Y29sb3IKCnByaW50KHNlc3Npb25JbmZvKCksbG9jYWxlPUZBTFNFKQoKc2VsZWN0IDwtIGRwbHlyOjpzZWxlY3QKY291bnQgPC0gZHBseXI6OmNvdW50CnJlbmFtZSA8LSBkcGx5cjo6cmVuYW1lCmBgYAoKIyMjIFBhcmFtZXRlcnMKCiptb2RpZnkgaGVyZSoKCmBgYHtyIHBhcmFtc30KIyBGaWxlcwoKCiNkZWZ0YWJsZSA8LSAifi9ha3V3YWthZG8va3V3YWthZG8vQlJCU2VxL0gzbW0xOF9Eb3hfMDQzMmxhbmUyL0ZpbmFsX1JzZXJ2ZXJfMTkxMjAzL2RlZnRhYmxlX0JSQl9ub3VtaV9uZXdfMTkwNTIwX2ZpbjE5MTIwNXZlci50eHQiICNVbWnoo5zmraPjgarjgZcgKEJSQikKCmRlZnRhYmxlIDwtICIvaG9tZS9ndWVzdEEvbzcwNTc4YS9ha3V3YWthZG8va3V3YWthZG8vQlJCU2VxL0gzbW0xOF9Eb3hfMDQzMmxhbmUyL0ZpbmFsX0xhc3RfUnNlcnZlcl8yMDA4MTEvZGVmdGFibGVfQlJCX25vdW1pX25ld18xOTA1MjBfTGFzdDIwMjAwODExdmVyLnR4dCIKCiNkZWZ0YWJsZSA8LSAifi9ha3V3YWthZG8va3V3YWthZG8vQlJCU2VxL0gzbW0xOF9Eb3hfMDQzMmxhbmUyL0ZpbmFsX1JzZXJ2ZXJfMTkxMjAzL2RlZnRhYmxlX0JSQl9ub3VtaV9uZXdfMTkwNTIwX2ZpbjE5MTIwNXZlci50eHQiICNVbWnoo5zmraPjgarjgZcgKEJSQikKCgojZGVmdGFibGUgPC0gImRlZnRhYmxlX0JSQl9ub3VtaV9uZXdfMTkwNTIwLnR4dCIgI1VtaeijnOato+OBquOBlyAoQlJCKQoKI2RlZnRhYmxlIDwtICJ+L2FrdXdha2Fkby9rdXdha2Fkby9CUkJTZXEvSDNtbTE4X0RveF8wNDMybGFuZTIvZGVmdGFibGVfQlJCX25vdW1pX25ld18xOTA1MjAudHh0IiAjVW1p6KOc5q2j44Gq44GXIChCUkIpCgoKIyMgRGF0YSBzZWxlY3Rpb24gKGZpbHRlciByb3dzIG9mIGRlZnRhYmxlKQojdXNlIDwtIHF1byghZ3JlcGwoIl4xOCIsZ3JvdXApICYgKGdyb3VwICE9ICJOYy1taW51c1RyeWQiKSkKI3VzZSA8LSBxdW8oVFJVRSkgIyB1c2UgYWxsCnVzZSA8LSBxdW8odHlwZSAhPSAiQzJDMTIiKQoKIyBTcGVjaWVzIHNwZWNpZmljIHBhcmFtZXRlcnMKc3BlY2llcyA8LSAiTXVzIG11c2N1bHVzIgpiaW9tYXJ0YW5uIDwtICJtbXVzY3VsdXNfZ2VuZV9lbnNlbWJsIgptYXhjaHJvbSA8LSAxOSAjIDE5OiBtb3VzZSwgMjI6IGh1bWFuCgoKIyBHcmFwaGljcwojIGFlc3RoZXRpYyBtYXBwaW5nIG9mIGxhYmVscwojbXlhZXMgPC0gYWVzKGNvbG91cj1lbnp5bWUsc2hhcGU9bGVnLGxhYmVsPXJlcCkgCiNteWFlcyA8LSBhZXMoY29sb3VyPWdyb3d0aCxzaGFwZT10eXBlLHNpemU9Y291bnQpICPjg6njg5njg6vjgarjgZcKI215YWVzIDwtIGFlcyhjb2xvdXI9Z3Jvd3RoLHNoYXBlPXR5cGUsbGFiZWw9cmVwbGljYXRlLHNpemU9Y291bnQpICPjg6njg5njg6vjgYLjgooKI215YWVzIDwtIGFlcyhjb2xvdXI9ZW56eW1lLHNoYXBlPWxlZyxsYWJlbD1yZXBsaWNhdGUpICPjg6njg5njg6vjgYLjgooKI215YWVzIDwtIGFlcyhjb2xvdXI9ZW56eW1lLHNoYXBlPWxlZyxsYWJlbD1mYWN0b3IocmVwKSkKI215YWVzIDwtIGFlcyhjb2xvdXI9dHlwZSwgc2hhcGU9cmV2Y3JvLCBsYWJlbD1yZWFkLCBzaXplPWNvdW50KQojbXlhZXMgPC0gYWVzKGNvbG91cj10eXBlLCBzaGFwZT1yZXZjcm8sIGxhYmVsPXJlYWQpCgojbXlhZXMgPC0gYWVzKGNvbG91cj1ncm93dGgsc2hhcGU9dHlwZSxsYWJlbD1yZXBsaWNhdGUsc2l6ZT1jb3VudCkgI+ODqeODmeODq+OBguOCigojbXlhZXMgPC0gYWVzKGNvbG91cj10aW1lLHNoYXBlPXR5cGUsc2l6ZT1jb3VudCxsYWJlbD1yZXBsaWNhdGUpCiNteWFlcyA8LSBhZXMoY29sb3VyPVdUX0tPX2ludGFjdF9DVFgsIHNoYXBlPURheSxzaXplPWNvdW50LGxhYmVsPWZfbSkKCiNteWFlcyA8LSBhZXMoY29sb3VyPVdUX0tPX2ludGFjdF9DVFgsIHNoYXBlPURheSwgbGFiZWw9Zl9tKSAj44K144Kk44K644KS5aSJ44GI44GaCiNteWFlcyA8LSBhZXMoY29sb3VyPWdyb3d0aCxzaGFwZT10eXBlLGxhYmVsPXJlcGxpY2F0ZSxzaXplPWNvdW50KSAj44Op44OZ44Or44GC44KKCm15YWVzIDwtIGFlcyhjb2xvdXI9dGltZSxzaGFwZT10eXBlLGxhYmVsPXJlcCxzaXplPWNvdW50KSAj44Op44OZ44Or44GC44KKCm15YWVzMiA8LSBhZXMoY29sb3VyPXRpbWUsc2hhcGU9dHlwZSkgI2t1d2EgYWRkCgojIGNvbG9yIHBhbGV0dGUgb2YgcG9pbnRzOiBTZWUgdmlnbmV0dGUoImdnc2NpIikKbXljb2xvciA8LSBnZ3NjaTo6c2NhbGVfY29sb3JfYWFhcygpCgoKCiMgUENBL1VNQVAKc2NhbGVyb3dzIDwtIFRSVUUgIyBnZW5lLXdpc2Ugc2NhbGluZyAocGF0dGVybiBpcyB0aGUgbWF0dGVyPykKbnRvcCA8LSA1MDAgIyBudW1iZXIgb2YgdG9wLW4gZ2VuZXMgd2l0aCBoaWdoIHZhcmlhbmNlCnNlZWQgPC0gMTIzICMgc2V0IGFub3RoZXIgbnVtYmVyIGlmIFVNQVAgbG9va3Mgbm90IGdvb2QKbl9uZWkgPC0gNiAgIyBudW1iZXIgb2YgbmVpZ2hib3JpbmcgZGF0YSBwb2ludHMgaW4gVU1BUCAj44GT44GT44KS44Gp44GG44GX44Gf44KJ44GE44GE77yfCgoKIyBERVNlcTIKI21vZGVsIDwtIH5ncm91cG4rbGVhZCAjZGF0ZeOCgui/veWKoAojbW9kZWwgPC0gfmxlZyArIGVuenltZSArIGxlZzplbnp5bWUKI21vZGVsIDwtIH50eXBlK2dyb3d0aCMrdHlwZTpncm93dGgKI21vZGVsIDwtIH5ncm91cCtsZWFkCgoKI21vZGVsIDwtIH5ncm91cAojbW9kZWwgPC0gfnR5cGUrZ3Jvd3RoK3R5cGU6Z3Jvd3RoICPjgZPjgozjgafjga/nm7jkupLkvZznlKjjgYzlhaXjgaPjgabjgYTjgarjgYQKI21vZGVsIDwtIH50eXBlK2dyb3d0aCAj44GT44KM44Gn44Gv55u45LqS5L2c55So44GM5YWl44Gj44Gm44GE44Gq44GECgoKbW9kZWwgPC0gfmdyb3VwCiNtb2RlbCA8LSB+dHlwZStncm93dGgrZ3Jvd3RoOnR5cGUKCmZkciA8LSAwLjEgIyBhY2NlcHRhYmxlIGZhbHNlIGRpc2NvdmVyeSByYXRlCmxmY3RocmV0aCA8LSBsb2cyKDEpICMgdGhyZXNob2xkIGluIGFicyhsb2cyRkMpCgojIGNvbnRyb2xzIHNob3VsZCBiZSBwbGFjZWQgaW4gdGhlIHJpZ2h0CmNvbnRyYXN0IDwtIGxpc3QoCiAgCiAgZ3JvdXBfVUlfRG94cGx1c192c19taW51cyA9IGMoImdyb3VwIiwgIkJSQl9VSV9Eb3hQbHVzIiwgIkJSQl9VSV9Eb3hNaW51cyIpLAogIGdyb3VwXzBoX0RveHBsdXNfdnNfbWludXMgPSBjKCJncm91cCIsICJCUkJfMGhfRG94UGx1cyIsICJCUkJfMGhfRG94TWludXMiKSwKICBncm91cF8yNGhfRG94cGx1c192c19taW51cyA9IGMoImdyb3VwIiwgIkJSQl8yNGhfRG94UGx1cyIsICJCUkJfMjRoX0RveE1pbnVzIiksCiAgZ3JvdXBfNDhoX0RveHBsdXNfdnNfbWludXMgPSBjKCJncm91cCIsICJCUkJfNDhoX0RveFBsdXMiLCAiQlJCXzQ4aF9Eb3hNaW51cyIpCiAgCiAgCiAgI2dyb3VwX1VJX0RveHBsdXNfdnNfbWludXMgPSBjKCJncm91cCIsICJEb3hwbHVzX1VJIiwgIkRveG1pbnVzX1VJIiksCiAgI2dyb3VwX0RpZmYwaF9Eb3hwbHVzX3ZzX21pbnVzID0gYygiZ3JvdXAiLCAiRG94cGx1c19EaWZmMGgiLCAiRG94bWludXNfRGlmZjBoIiksCiAgI2dyb3VwX0RpZmYyNGhfRG94cGx1c192c19taW51cyA9IGMoImdyb3VwIiwgIkRveHBsdXNfRGlmZjI0aCIsICJEb3htaW51c19EaWZmMjRoIiksCiAgI2dyb3VwX0RpZmY0OGhfRG94cGx1c192c19taW51cyA9IGMoImdyb3VwIiwgIkRveHBsdXNfRGlmZjQ4aCIsICJEb3htaW51c19EaWZmNDhoIikKICAKICAKICAjSW50ZXJjZXB0ID0gbGlzdCgiSW50ZXJjZXB0IiksICMgcmVmZXJlbmNlIGxldmVsCiAgI2xlZ19MdnNSID0gYygibGVnIiwgIkwiLCAiUiIpLAogICNlbnpfS3ZzQyA9IGMoImVuenltZSIsIksiLCJDIikKICAjbGVnTC5lbnpLID0gbGlzdCgibGVnTC5lbnp5bWVLIikgIyBpbnRlcmFjdGlvbgogIAogICN0eXBlX0RveHBsdXNfdnNfbWludXMgPSBjKCJ0eXBlIiwgIkRveHBsdXMiLCAiRG94bWludXMiKQopCmBgYAoKCgojIyMgUmV0cmlldmUgQmlvbWFydAoKYGBge3IgYmlvbWFydCwgY2FjaGU9VFJVRX0KaWYoIWV4aXN0cygiZTJnIikpewogICNlbnNlbWJsIDwtIGJpb21hUnQ6OnVzZU1hcnQoIkVOU0VNQkxfTUFSVF9FTlNFTUJMIixob3N0PSJhc2lhLmVuc2VtYmwub3JnIikKICAjZW5zZW1ibCA8LSBiaW9tYVJ0Ojp1c2VNYXJ0KCJFTlNFTUJMX01BUlRfRU5TRU1CTCIsaG9zdD0idXN3ZXN0LmVuc2VtYmwub3JnIikKICBlbnNlbWJsIDwtIGJpb21hUnQ6OnVzZU1hcnQoIkVOU0VNQkxfTUFSVF9FTlNFTUJMIixob3N0PSJ1c2Vhc3QuZW5zZW1ibC5vcmciKQogIG1hcnQgPC0gYmlvbWFSdDo6dXNlRGF0YXNldChiaW9tYXJ0YW5uLG1hcnQ9ZW5zZW1ibCkKICBlMmcgPC0gYmlvbWFSdDo6Z2V0Qk0oYXR0cmlidXRlcz1jKCJlbnNlbWJsX2dlbmVfaWQiLCJleHRlcm5hbF9nZW5lX25hbWUiLAogICAgImdlbmVfYmlvdHlwZSIsImNocm9tb3NvbWVfbmFtZSIpLCBtYXJ0PW1hcnQpICU+JSBhc190aWJibGUgJT4lCiAgcmVuYW1lKAogICAgZW5zX2dlbmUgPSBlbnNlbWJsX2dlbmVfaWQsCiAgICBleHRfZ2VuZSA9IGV4dGVybmFsX2dlbmVfbmFtZSwKICAgIGJpb3R5cGUgPSBnZW5lX2Jpb3R5cGUsCiAgICBjaHIgPSBjaHJvbW9zb21lX25hbWUKICApCn0KYW5ub3RhdGUgPC0gcGFydGlhbChyaWdodF9qb2luLGUyZyxieT0iZW5zX2dlbmUiKQoKIy0tLS0tIwpucm93KGUyZykKI3JlYWRyOjp3cml0ZV9jc3YoZTJnLCJlbnNlbWJsZV9saXN0X2FzaWEuY3N2IikKI3JlYWRyOjp3cml0ZV9jc3YoZTJnLCJlbnNlbWJsZV9saXN0X3Vzd2VzdC5jc3YiKQpyZWFkcjo6d3JpdGVfY3N2KGUyZywiZW5zZW1ibGVfbGlzdF91c2Vhc3QuY3N2IikKYGBgCgojIyMgTG9hZCBjb3VudHMKCmBgYHtyIGxvYWRVTUl9CmRlZiA8LSByZWFkcjo6cmVhZF90c3YoZGVmdGFibGUpICU+JSBmaWx0ZXIoISF1c2UpCnByaW50KGRlZikKCiNkZWYkZ3Jvd3RoIDwtIGZhY3RvcihkZWYkZ3Jvd3RoLGxldmVscyA9YygiVUkiLCJEaWZmMGgiLCJEaWZmMjRoIiwiRGlmZjQ4aCIpKQojZGVmJHR5cGUgPC0gZmFjdG9yKGRlZiR0eXBlLGxldmVscyA9YygiRG94bWludXMiLCJEb3hwbHVzIikpCgojZmFjdG9yKGRlZiRncm93dGgsbGV2ZWxzID1jKCJVSSIsIkRpZmYwaCIsIkRpZmYyNGgiLCJEaWZmNDhoIikpCiMgWzFdIFVJICAgICAgVUkgICAgICBVSSAgICAgIFVJICAgICAgVUkgICAgICBVSSAgICAgIFVJICAgICAgVUkgICAgICBEaWZmMGggIERpZmYwaCAgRGlmZjBoICBEaWZmMGggIERpZmYwaCAgRGlmZjBoICBEaWZmMGggIERpZmYwaCAgRGlmZjI0aCBEaWZmMjRoIERpZmYyNGggRGlmZjI0aAojWzIxXSBEaWZmMjRoIERpZmYyNGggRGlmZjI0aCBEaWZmMjRoIERpZmY0OGggRGlmZjQ4aCBEaWZmNDhoIERpZmY0OGggRGlmZjQ4aCBEaWZmNDhoIERpZmY0OGggRGlmZjQ4aAojTGV2ZWxzOiBVSSBEaWZmMGggRGlmZjI0aCBEaWZmNDhoCgoKIyMjIy0tLSBOZXcgLS0tIyMjIyAobm8gVU1JID8pCiMgU2V0IHJlZmVyZW5jZSBsZXZlbHMgYWNjb3JkaW5nIHRvIHRoZSBjb250cmFzdApmb3IoeCBpbiBrZWVwKGNvbnRyYXN0LGlzLmNoYXJhY3RlcikpCiAgZGVmW1t4WzFdXV0gPC0gcmVsZXZlbChmYWN0b3IoZGVmW1t4WzFdXV0pLHhbM10pCgp1bWkgPC0gZGVmJGZpbGUgJT4lIHVuaXF1ZSAlPiUgdGliYmxlKGZpbGU9LikgJT4lIAogIGRwbHlyOjptdXRhdGUoZGF0YT1tYXAoZmlsZSxyZWFkcjo6cmVhZF90c3YscHJvZ3Jlc3M9RkFMU0UpKSAlPiUKICB1bm5lc3QoKSAlPiUgZHBseXI6OnJlbmFtZShiYXJjb2RlPWNlbGwpICU+JQogIGRwbHlyOjppbm5lcl9qb2luKHNlbGVjdChkZWYsZmlsZSxiYXJjb2RlLHNhbXBsZSksLixjKCJmaWxlIiwiYmFyY29kZSIpKSAlPiUKICBzZWxlY3QoLWZpbGUsLWJhcmNvZGUpICU+JSBkcGx5cjo6cmVuYW1lKGVuc19nZW5lPWdlbmUpCgpwcmludCh1bWkpCgojIyBzYW1wbGUsIGJhcmNvZGUsIGZpbGUg44KS5b+Y44KM44Ga44Gr77yBCgptYXQgPC0gdW1pICU+JSBhbm5vdGF0ZSAlPiUKICBkcGx5cjo6bXV0YXRlKGNocj1mYWN0b3IoY2hyLGMoMTptYXhjaHJvbSwiWCIsIlkiLCJNVCIpKSkgJT4lCiAgZmlsdGVyKCFpcy5uYShjaHIpKSAlPiUgc3ByZWFkKHNhbXBsZSxjb3VudCxmaWxsPTApCgojIyB0byBjaGVjayByZWFkIHZpYXMsIHRoaXMgYWRkIHJlYWQgbnVtYmVyIGFzICJuIiBjb2x1bW4gKDIwMTkvNC8xOSkKZGVmIDwtIHVtaSAlPiUgY291bnQoc2FtcGxlLHd0PWNvdW50KSAlPiUgZHBseXI6OmlubmVyX2pvaW4oZGVmLC4pICU+JSBkcGx5cjo6cmVuYW1lKGNvdW50PW4pCiMjIyMtLS0tLS0tLS0tLSMjIyMgCgoKCgojIFNldCByZWZlcmVuY2UgbGV2ZWxzIGFjY29yZGluZyB0byB0aGUgY29udHJhc3QKI2Zvcih4IGluIGtlZXAoY29udHJhc3QsaXMuY2hhcmFjdGVyKSkKIyAgZGVmW1t4WzFdXV0gPC0gcmVsZXZlbChmYWN0b3IoZGVmW1t4WzFdXV0pLHhbM10pCgojdW1pIDwtIGRlZiRmaWxlICU+JSB1bmlxdWUgJT4lIHRpYmJsZShmaWxlPS4pICU+JSAKIyAgbXV0YXRlKGRhdGE9bWFwKGZpbGUscmVhZHI6OnJlYWRfdHN2LHByb2dyZXNzPUZBTFNFKSkgJT4lCiMgIHVubmVzdCgpICU+JSBkcGx5cjo6cmVuYW1lKGJhcmNvZGU9Y2VsbCkgJT4lCiMgIGlubmVyX2pvaW4oc2VsZWN0KGRlZixmaWxlLGJhcmNvZGUsc2FtcGxlKSwuLGMoImZpbGUiLCJiYXJjb2RlIikpICU+JQojICBzZWxlY3QoLWZpbGUsLWJhcmNvZGUpICU+JSBkcGx5cjo6cmVuYW1lKGVuc19nZW5lPWdlbmUpCgojbWF0IDwtIHVtaSAlPiUgYW5ub3RhdGUgJT4lCiMgIG11dGF0ZShjaHI9ZmFjdG9yKGNocixjKDE6bWF4Y2hyb20sIlgiLCJZIiwiTVQiKSkpICU+JQojICBmaWx0ZXIoIWlzLm5hKGNocikpICU+JSBzcHJlYWQoc2FtcGxlLGNvdW50LGZpbGw9MCkKCnByaW50KG1hdCkKCiMjIHRvIGNoZWNrIHJlYWQgdmlhcywgdGhpcyBhZGQgcmVhZCBudW1iZXIgYXMgIm4iIGNvbHVtbiAoMjAxOS80LzE5KQojZGVmIDwtIHVtaSAlPiUgY291bnQoc2FtcGxlLHd0PWNvdW50KSAlPiUgaW5uZXJfam9pbihkZWYsLikgJT4lIGRwbHlyOjpyZW5hbWUoY291bnQ9bikKCnByaW50KGRlZikKCgojIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMjCiMg56K66KqNICgyMDE5MTIwNCkg77yS44Gk44Gu5YCk44Gv5LiA57eS44GL77yfCiMg55Sf44Gu44OH44O844K/44Kr44Km44Oz44OI5Lit44Gu6YG65Lyd5a2Q57eP5pWwCgp1bWkgJT4lIGdyb3VwX2J5KGVuc19nZW5lKSAlPiUgc3VtbWFyaXplICU+JSBucm93KCkKCnVtaSAlPiUgc3ByZWFkKHNhbXBsZSxjb3VudCxmaWxsPTApICU+JSBucm93KCkKCm1hdCAlPiUgbnJvdygpCm1hdCAlPiUgZmlsdGVyKGNociE9Ik1UIikgJT4lIG5yb3coKSAjIE1U44Gq44GXCgojIG1hdOOBp+OBr+OAgWNocuetieOBjOS4jeaYjuOBquOCguOBruOBr+ecgeOBhOOBpuOBhOOCi+OAggojIERFR+OBp+OBr+OAgeOBleOCieOBq01U44KC55yB44GE44Gm44GE44KL44CCCiMjPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IyMKCmBgYAoKIyMjIFJlYWRzIGJyZWFrZG93bgoKIyMjIyBUb3RhbCByZWFkcwoKYGBge3IgdG90YWxSZWFkcywgZmlnLndpZHRoPTcsZmlnLmhlaWdodD01fQpieWNociA8LSBtYXQgJT4lIHNlbGVjdCgtKDE6MykpICU+JQogIGdhdGhlcigic2FtcGxlIiwiY291bnQiLC1jaHIpICU+JQogIGdyb3VwX2J5KGNocixzYW1wbGUpICU+JSBzdW1tYXJpc2UodG90YWw9c3VtKGNvdW50KSkgJT4lIHVuZ3JvdXAKCmdncGxvdChieWNocixhZXMocmVvcmRlcihzYW1wbGUsZHBseXI6OmRlc2Moc2FtcGxlKSksdG90YWwvMWU2LGZpbGw9Y2hyKSkgKwogIHRoZW1lX2xpbmVkcmF3KCkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgY29vcmRfZmxpcCgpICsKICB4bGFiKCJzYW1wbGUiKSArIHlsYWIoIm1pbGxpb24gcmVhZHMiKSArIGdnc2NpOjpzY2FsZV9maWxsX2lndigpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IHJldihsZXZlbHMoc2FtcGxlKSkpCgoKYGBgCgojIyMjIEJpb3R5cGUKCmBgYHtyIGJpb3R5cGUsZmlnLndpZHRoPTgsZmlnLmhlaWdodD03fQpidCA8LSBtYXQgJT4lIHNlbGVjdCgtYygxLDIsNCkpICU+JSBncm91cF9ieShiaW90eXBlKSAlPiUKICBzdW1tYXJpc2VfYWxsKHN1bSkgJT4lIGZpbHRlcl9hdCgtMSxhbnlfdmFycyguID4gMTAwMCkpCmJ0ICU+JSB0aWJibGU6OmNvbHVtbl90b19yb3duYW1lcygiYmlvdHlwZSIpICU+JQogIGFzLm1hdHJpeCAlPiUgdCAlPiUgbW9zYWljcGxvdChsYXM9MixzaGFkZT1UUlVFKQpgYGAKCiMjIyBDb3JyZWxhdGlvbnMKCmRyb3Agcm93cyB3aXRoIGFsbCAwIC0+ICsxLzIgLT4gZ2VvbS5zY2FsZSAtPiBsb2cgLT4gUGVhcnNvbidzCgpgYGB7ciBtYWtlbWF0LCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTd9Cm1hdGYgPC0gbWF0ICU+JSBmaWx0ZXIoY2hyIT0iTVQiKSAlPiUgZmlsdGVyX2F0KC0oMTo0KSxhbnlfdmFycyguID4gMCkpClggPC0gbWF0ZiAlPiUgc2VsZWN0KC0oMTo0KSkgJT4lIGFzLm1hdHJpeApyb3duYW1lcyhYKSA8LSBtYXRmJGVuc19nZW5lCmxYIDwtIGxvZyhnc2NhbGUoWCswLjUpKQpSIDwtIGNvcihsWCk7IGRpYWcoUikgPC0gTkEKcGhlYXRtYXA6OnBoZWF0bWFwKFIsY29sb3I9dmlyaWRpczo6dmlyaWRpcygyNTYpKQpgYGAKCiMjIyBEaW1lbnNpb24gcmVkdWN0aW9uCgpgYGB7ciBQQ0EsZmlnLndpZHRoPTQsZmlnLmhlaWdodD0zfQojIHNldCBzY2FsZT1UUlVFIGlmIHRoZSBwYXR0ZXJucyAobm90IGxldmVsKSBpcyB0aGUgbWF0dGVyCnAgPC0gcHJjb21wKHQobFhbcmFuaygtYXBwbHkobFgsMSx2YXIpKSA8PSBudG9wLF0pLHNjYWxlPXNjYWxlcm93cyxjZW50ZXI9VFJVRSkKc2NyZWVwbG90KHAsbGFzPTIsbWFpbj0iSW1wb3J0YW5jZSIpCnByaW50KHN1bW1hcnkocCkkaW1wWyxzZXEobWluKDEwLG5jb2woWCkpKV0pCmBgYAoKYGBge3IgbWFrZXNjb3JlREZ9CmxhYmVsIDwtIGRlZiAlPiUgZmlsdGVyKHNhbXBsZSAlaW4lIGNvbG5hbWVzKFgpKQpkZiA8LSBkYXRhLmZyYW1lKHAkeCkgJT4lIGFzX3RpYmJsZShyb3duYW1lcz0ic2FtcGxlIikgJT4lCiAgaW5uZXJfam9pbihsYWJlbCwuKSAlPiUgc2VsZWN0KC1maWxlKQoKcHJpbnQoZGYpCmBgYAoKYGBge3IgcHJveGltaXR5LGZpZy53aWR0aD02LGZpZy5oZWlnaHQ9NH0KZ2dwb2ludHMoZGYsbW9kaWZ5TGlzdChhZXMoUEMxLFBDMiksbXlhZXMpKQpzZXQuc2VlZChzZWVkKQp1bSA8LSB1d290Ojp1bWFwKHAkeCxuX25laSwyKQpkZiA8LSBhc190aWJibGUodW0pICU+JSByZW5hbWUoVU1BUDE9VjEsVU1BUDI9VjIpICU+JSBiaW5kX2NvbHMoZGYpCmdncG9pbnRzKGRmLG1vZGlmeUxpc3QoYWVzKFVNQVAxLFVNQVAyKSxteWFlcykpCgpwcmludChkZikKCiMjICBrdXdha2FkbyDlpInmm7QgIyMKZ2dwb2ludHMgPC0gZnVuY3Rpb24oeCwuLi4pIAogIGdncGxvdCh4LC4uLikgKyBnZW9tX3BvaW50KHN0cm9rZT0xKSArIHRoZW1lX21pbmltYWwoKSArIG15Y29sb3IKCiNnZ3BvaW50cyhkZixtb2RpZnlMaXN0KGFlcyhQQzEsUEMyKSxteWFlczIpKQojc2V0LnNlZWQoc2VlZCkKI3VtIDwtIHV3b3Q6OnVtYXAocCR4LG5fbmVpLDIpCiNkZiA8LSBhc190aWJibGUodW0pICU+JSByZW5hbWUoVU1BUDE9VjEsVU1BUDI9VjIpICU+JSBiaW5kX2NvbHMoZGYpCiNnZ3BvaW50cyhkZixtb2RpZnlMaXN0KGFlcyhVTUFQMSxVTUFQMiksbXlhZXMyKSkKIyMgIyMgIyMgIyMKYGBgCgojIyMgREVTZXEyCgojIyMjIEZpdCBtb2RlbAoKYGBge3IgZGVzZXEyfQpkZHMgPC0gREVTZXEyOjpERVNlcURhdGFTZXRGcm9tTWF0cml4KFhbLGxhYmVsJHNhbXBsZV0sbGFiZWwsbW9kZWwpCmRkcyA8LSBERVNlcTI6OkRFU2VxKGRkcykKCgojPT09PT0jCgpkZHMgPC0gREVTZXEyOjplc3RpbWF0ZVNpemVGYWN0b3JzKGRkcykKbm9ybSA8LSBERVNlcTI6OmNvdW50cyhkZHMsbm9ybWFsaXplZD1UUlVFKSAjREVH44KS5Y+W44Gj44Gf5b6M44Gu44Kv44Op44K544K/44Oq44Oz44Kw44Gr5L2/44GG44CCCgpub3JtYWxpemVkY291bnQgPC0gYXMuZGF0YS5mcmFtZShub3JtKSAlPiUgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oImVuc19nZW5lIikgJT4lIGFzX3RpYmJsZQpyZWFkcjo6d3JpdGVfY3N2KG5vcm1hbGl6ZWRjb3VudCwgIi4vSDNtbTE4S09fM1QzX0RveF9ub3JtQ291bnQuY3N2IikKCm5vcm1hbGl6ZWRjb3VudCAlPiUgaW5uZXJfam9pbihlMmcsIGJ5ID0gImVuc19nZW5lIikgICU+JSBkcGx5cjo6c2VsZWN0KCJlbnNfZ2VuZSIsImV4dF9nZW5lIiwgImJpb3R5cGUiLCJjaHIiLCBhbGxfb2YobGFiZWwkc2FtcGxlKSkgJT4lIHJlYWRyOjp3cml0ZV9jc3YoIi4vSDNtbTE4S09fM1QzX0RveF9ub3JtQ291bnRfZ2VuZW5hbWUuY3N2IikKCiNjb3VudF9kZHMgPC0gZXN0aW1hdGVTaXplRmFjdG9ycyhkZHMpCiNjb3VudHMoY291bnRfZGRzLCBub3JtYWxpemVkPVRSVUUpCgojIyMjLS0tICsgc2l6ZSBmYWN0b3JzIOOCkuabuOOBjeWHuuOBlyAtLS0tLS0tLS0tLS0tLS0tLS0jIyMjCmFzLmRhdGEuZnJhbWUoREVTZXEyOjpzaXplRmFjdG9ycyhkZHMpKSAgJT4lIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGUiKSAlPiUgcmVhZHI6OndyaXRlX2NzdigiLi9IM21tMThLT18zVDNfRG94X19zaXplZmFjdG9ycy5jc3YiKQoKCgpgYGAKCgp2c3QgPT4geiBzY29yZQoKYGBge3IgenNjb3JlIDIwMDgxMWFkZH0KCnZzZCA8LSBERVNlcTI6OnZzdChkZHMpICNub3JtYWxpemVkIGNvdW5044GM5YWl44Gj44Gm44GE44KL44CCKHZzdOOBi3Jsb2cpClhkIDwtIFN1bW1hcml6ZWRFeHBlcmltZW50Ojphc3NheSh2c2QpICMg5YWo44Gm6YG45oqeKDIwMDMyNikgMjAxOTA5MjDjgpLlhYPjgasgKDE5MTAyNCkKWHMgPC0gWGQgJT4lIHQgJT4lIHNjYWxlICU+JSB0Cgp6c2NvcmUgPC0gWHMgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oImVuc19nZW5lIikgJT4lIGFzX3RpYmJsZQp6c2NvcmVfdHlwZSA8LSB6c2NvcmUgICU+JSBhbm5vdGF0ZSAlPiUgZHBseXI6OnNlbGVjdCgiZW5zX2dlbmUiLCJleHRfZ2VuZSIsICJiaW90eXBlIiwiY2hyIiwgYWxsX29mKGxhYmVsJHNhbXBsZSkpCgoKCnJlYWRyOjp3cml0ZV9jc3YoenNjb3JlLCAiSDNtbTE4S09fM1QzX0RveF9fenNjb3JlX2FsbC5jc3YiKQpyZWFkcjo6d3JpdGVfY3N2KHpzY29yZV90eXBlLCAiSDNtbTE4S09fM1QzX0RveF9fenNjb3JlX3R5cGVfYWxsLmNzdiIpCgpucm93KHpzY29yZV90eXBlKQoKYGBgCiMjIyMgRGlhZ25vc3RpY3MgcGxvdAoKYGBge3IgZGlhZ25vc3RpY3MsZmlnLndpZHRoPTcsZmlnLmhlaWdodD01fQpERVNlcTI6OnNpemVGYWN0b3JzKGRkcykgJT4lCiAge3RpYmJsZShzYW1wbGU9bmFtZXMoLiksc2l6ZUZhY3Rvcj0uKX0gJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUsc2l6ZUZhY3RvcikpICsgdGhlbWVfbWluaW1hbCgpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgY29vcmRfZmxpcCgpCkRFU2VxMjo6cGxvdERpc3BFc3RzKGRkcykKYGBgCgoKIyMjIyBFeHRyYWN0IHJlc3VsdHMKMTkxMjA15L+u5q2jCgpgYGB7ciBleHRyYWN0UmVzfQpyZXMgPC0gbWFwcGx5KGZ1bmN0aW9uKHgpCiAgREVTZXEyOjpyZXN1bHRzKGRkcyx4LGxmY1RocmVzaG9sZD1sZmN0aHJldGgsYWxwaGE9ZmRyKQosY29udHJhc3QpCgpwcmludChmZHIpCgoKIyAyMDA4MTHkv67mraMKcmVfYWxsIDwtIG1hcChyZXMsYXNfdGliYmxlLHJvd25hbWVzPSJlbnNfZ2VuZSIpICU+JQogIHRpYmJsZShhc3BlY3Q9ZmFjdG9yKG5hbWVzKC4pLG5hbWVzKC4pKSxkYXRhPS4pICU+JQogIG11dGF0ZShkYXRhPW1hcChkYXRhLGFubm90YXRlKSkgJT4lCiAgdW5uZXN0KGNvbHMgPSAiZGF0YSIpCgpyZSA8LSByZV9hbGwgJT4lIGZpbHRlcihwYWRqPGZkcikgIzE5MTEyMOS/ruatoyB1bm5lc3QoKSAKCgojcmUgPC0gbWFwKHJlcyxhc190aWJibGUscm93bmFtZXM9ImVuc19nZW5lIikgJT4lCiMgIHRpYmJsZShhc3BlY3Q9ZmFjdG9yKG5hbWVzKC4pLG5hbWVzKC4pKSxkYXRhPS4pICU+JQojICBtdXRhdGUoZGF0YT1tYXAoZGF0YSxhbm5vdGF0ZSkpICU+JQojICB1bm5lc3QoY29scyA9ICJkYXRhIikgJT4lIGZpbHRlcihwYWRqPGZkcikgIzE5MTEyMOS/ruatoyB1bm5lc3QoKSAKCmZjIDwtIHJlICU+JSBzZWxlY3QoMTo3KSAlPiUgc3ByZWFkKGFzcGVjdCxsb2cyRm9sZENoYW5nZSxmaWxsPTApCgppbWFwKHJlcyx+ewogIGNhdChwYXN0ZTAoIi0tICIsLnksIiAtLSIpKQogIERFU2VxMjo6c3VtbWFyeSgueCkgIzE5MTEyMOS/ruatoyBERVNlcTI6OnN1bW1hcnkuREVTZXFSZXN1bHRzKC54KQp9KSAlPiUgaW52aXNpYmxlCmBgYAoKIyMjIEdTRUEKCmBgYHtyIEdTRUEsIHdhcm5pbmc9RkFMU0V9Cm1zaWcgPC0gbXNpZ2Ricjo6bXNpZ2RicihzcGVjaWVzKQpmZ3NlYV9tc2lnIDwtIHBhcnRpYWwoZmdzZWE6OmZnc2VhLHdpdGgobXNpZyxzcGxpdChnZW5lX3N5bWJvbCxnc19uYW1lKSkpCmdzY2F0IDwtIG1zaWcgJT4lIHNlbGVjdChnc19uYW1lLGdzX2NhdCxnc19zdWJjYXQpICU+JQogIGRpc3RpbmN0KCkgJT4lIHJlbmFtZShwYXRod2F5PWdzX25hbWUpCgojZ3NlYSA8LSByZSAlPiUgZmlsdGVyKGFzcGVjdCE9IkludGVyY2VwdCIpICU+JSBncm91cF9ieShhc3BlY3QpICU+JQojICBzdW1tYXJpc2UobDJmYz1saXN0KHNldE5hbWVzKGxvZzJGb2xkQ2hhbmdlLGV4dF9nZW5lKSkpICU+JQojICBtdXRhdGUoZ3NlPW1hcChsMmZjLGZnc2VhX21zaWcsbnBlcm09MTAwMDAsbWF4U2l6ZT01MDApKSAlPiUKIyAgc2VsZWN0KC1sMmZjKSAlPiUgdW5uZXN0ICU+JSBhcnJhbmdlKC1ORVMpICU+JSByaWdodF9qb2luKGdzY2F0LC4pICU+JQojICBtdXRhdGUobGVhZGluZ0VkZ2U9bWFwX2NocihsZWFkaW5nRWRnZSxwYXN0ZSxjb2xsYXBzZT0iLCIpKQoKIyBnc2VhIOS/ruato3ZlciBbMjAxOTA2MjFdCiNnc2VhIDwtIHJlICU+JSBmaWx0ZXIoYXNwZWN0IT0iSW50ZXJjZXB0IikgJT4lIGdyb3VwX2J5KGFzcGVjdCkgJT4lCiMgIHN1bW1hcmlzZShsMmZjPWxpc3Qoc2V0TmFtZXMobG9nMkZvbGRDaGFuZ2UsZXh0X2dlbmUpKSkgJT4lCiMgIG11dGF0ZShnc2U9bWFwKGwyZmMsZmdzZWFfbXNpZyxucGVybT0xMDAwMCxtYXhTaXplPTUwMCkpICU+JQojICBzZWxlY3QoLWwyZmMpICU+JSB1bm5lc3QgJT4lIGFycmFuZ2UoLU5FUykgJT4lIHJpZ2h0X2pvaW4oZ3NjYXQsLikgJT4lCiMgIG11dGF0ZShsZWFkaW5nRWRnZT1tYXBfY2hyKGxlYWRpbmdFZGdlLHBhc3RlLGNvbGxhcHNlPSIsIikpICU+JQojICBncm91cF9ieShhc3BlY3QsZ3NfY2F0LGdzX3N1YmNhdCkgJT4lCiMgIG11dGF0ZShwYWRqPXAuYWRqdXN0KHB2YWwsIkJIIikpICU+JSB1bmdyb3VwKCkKCiMgZ3NlYSDkv67mraN2ZXIgWzIwMTkwNjI3XQpnc2VhIDwtIHJlICU+JSBmaWx0ZXIoYXNwZWN0IT0iSW50ZXJjZXB0IikgJT4lIGdyb3VwX2J5KGFzcGVjdCkgJT4lCiAgc3VtbWFyaXNlKGwyZmM9bGlzdChzZXROYW1lcyhsb2cyRm9sZENoYW5nZSxleHRfZ2VuZSkpKSAlPiUKICBmaWx0ZXIobWFwKGwyZmMsbGVuZ3RoKT4xMCkgJT4lCiAgbXV0YXRlKGdzZT1tYXAobDJmYyxmZ3NlYV9tc2lnLG5wZXJtPTEwMDAwLG1heFNpemU9NTAwKSkgJT4lCiAgc2VsZWN0KC1sMmZjKSAlPiUgdW5uZXN0ICU+JSBhcnJhbmdlKC1ORVMpICU+JSByaWdodF9qb2luKGdzY2F0LC4pICU+JQogIG11dGF0ZShsZWFkaW5nRWRnZT1tYXBfY2hyKGxlYWRpbmdFZGdlLHBhc3RlLGNvbGxhcHNlPSIsIikpICU+JQogIGdyb3VwX2J5KGFzcGVjdCxnc19jYXQsZ3Nfc3ViY2F0KSAlPiUKICBtdXRhdGUocGFkaj1wLmFkanVzdChwdmFsLCJCSCIpKSAlPiUgdW5ncm91cCgpCgpgYGAKCmBgYHtyIEhhbGxtYXJrLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpoYWxsbWFyayA8LSBnc2VhICU+JSBmaWx0ZXIoZ3NfY2F0PT0iSCIpICU+JQogIG11dGF0ZShwYXRod2F5PXN1YigiXkhBTExNQVJLXyIsIiIscGF0aHdheSkpICU+JSAKICBncm91cF9ieShhc3BlY3QpICU+JSBuZXN0ICU+JQogIG11dGF0ZShwbHQ9bWFwMihkYXRhLGFzcGVjdCx+CiAgICBnZ3Bsb3QoLngsYWVzKHJlb3JkZXIocGF0aHdheSxORVMpLE5FUyxmaWxsPXBhZGo8MC4xKSkgKwogICAgZ2d0aXRsZSgueSkgKyB4bGFiKCJIYWxsbWFyayBnZW5lIHNldHMiKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgdGhlbWVfbWluaW1hbCgpICsgY29vcmRfZmxpcCgpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBnZ3NjaTo6c2NhbGVfZmlsbF9hYWFzKCkpCiAgKQpwcmludChoYWxsbWFyayRwbHQpCmBgYAoKU2VlIE1TaWdEQiBDb2xsZWN0aW9uczogPGh0dHA6Ly9zb2Z0d2FyZS5icm9hZGluc3RpdHV0ZS5vcmcvZ3NlYS9tc2lnZGIvY29sbGVjdGlvbnMuanNwPgoKIyMjIFdyaXRlLW91dCB0YWJsZXMKCmBgYHtyIHdyaXRlb3V0fQoKI2NzdmZpbGVwYXRoIDwtICJCUkIwNDMybGFuZTJub3VtaV9IM21tMThfRG94IgoKaWYoZXhpc3RzKCJmYyIpKSAgIHJlYWRyOjp3cml0ZV9jc3YoZmMsIi4vMmd1bi9CUkIwNDMybGFuZTJub3VtaV9IM21tMThfRG94X2wyZmNfZmRyMHAxX19maW5hbDE5MTIwNV9sYXN0MjAwODExLmNzdiIpCmlmKGV4aXN0cygicmUiKSkgICByZWFkcjo6d3JpdGVfY3N2KHJlLCIuLzJndW4vQlJCMDQzMmxhbmUybm91bWlfSDNtbTE4X0RveF9yZXN1bHRzX2ZkcjBwMV9fZmluYWwxOTEyMDVfbGFzdDIwMDgxMS5jc3YiKQppZihleGlzdHMoInJlX2FsbCIpKSAgIHJlYWRyOjp3cml0ZV9jc3YocmVfYWxsLCIuLzJndW4vQlJCMDQzMmxhbmUybm91bWlfSDNtbTE4X0RveF9yZXN1bHRzYWxsX2ZkcjBwMV9fZmluYWwxOTEyMDVfbGFzdDIwMDgxMS5jc3YiKQppZihleGlzdHMoImdzZWEiKSkgcmVhZHI6OndyaXRlX2Nzdihnc2VhLCIuLzJndW4vQlJCMDQzMmxhbmUybm91bWlfSDNtbTE4X0RveF9nc2VhX2ZkcjBwMV9fZmluYWwxOTEyMDVfbGFzdDIwMDgxMS5jc3YiKQpgYGAKCgoKIyMjIFdyaXRlLW91dCB0YWJsZXMgSGFsbG1hcmsKCmBgYHtyIHdyaXRlb3V0IEhhbGxtYXJrfQojZ3NlYeOBrkhhbGxtYXJr44Gu44G/5pu444GN5Ye644GXCmhhbGxtYXJrX2dzZWEgPC0gZ3NlYSAlPiUgZmlsdGVyKGdzX2NhdD09IkgiKSAlPiUgbXV0YXRlKHBhdGh3YXk9c3ViKCJeSEFMTE1BUktfIiwiIixwYXRod2F5KSkgJT4lIGdyb3VwX2J5KGFzcGVjdCkKaWYoZXhpc3RzKCJoYWxsbWFya19nc2VhIikpIHJlYWRyOjp3cml0ZV9jc3YoaGFsbG1hcmtfZ3NlYSwiLi8yZ3VuL0JSQjA0MzJsYW5lMm5vdW1pX0gzbW0xOF9Eb3hfaGFsbG1hcmtfZ3NlYV9mZHIwcDFfX2ZpbmFsMTkxMjA1X2xhc3QyMDA4MTEuY3N2IikKYGBgCgojIyMgTUFwbG90Cgo1KjcgaW5jaAoKYGBge3IgbWFwbG90fQoKI21hcGxvdCA8LSBERVNlcTI6OnBsb3RNQShyZXMkZ3JvdXBfVUlfRG94cGx1c192c19taW51cywgeWxpbT1jKC0yLDIpKQojcHJpbnQobWFwbG90KQptYXBsb3QgPC0gREVTZXEyOjpwbG90TUEocmVzJGdyb3VwX1VJX0RveHBsdXNfdnNfbWludXMsIHlsaW09YygtNCw0KSwgbWFpbj0iVUlfRG94cGx1c192c19taW51cyIpCnByaW50KG1hcGxvdCkKCiNtYXBsb3QgPC0gREVTZXEyOjpwbG90TUEocmVzJGdyb3VwX0RpZmYwaF9Eb3hwbHVzX3ZzX21pbnVzICwgeWxpbT1jKC0yLDIpKQojcHJpbnQobWFwbG90KQptYXBsb3QgPC0gREVTZXEyOjpwbG90TUEocmVzJGdyb3VwXzBoX0RveHBsdXNfdnNfbWludXMsIHlsaW09YygtNCw0KSwgbWFpbj0iMGhfRG94cGx1c192c19taW51cyIpCnByaW50KG1hcGxvdCkKCiNtYXBsb3QgPC0gREVTZXEyOjpwbG90TUEocmVzJGdyb3VwX0RpZmYyNGhfRG94cGx1c192c19taW51cywgeWxpbT1jKC0yLDIpKQojcHJpbnQobWFwbG90KQptYXBsb3QgPC0gREVTZXEyOjpwbG90TUEocmVzJGdyb3VwXzI0aF9Eb3hwbHVzX3ZzX21pbnVzLCB5bGltPWMoLTQsNCksIG1haW49IjI0aF9Eb3hwbHVzX3ZzX21pbnVzIikKcHJpbnQobWFwbG90KQoKI21hcGxvdCA8LSBERVNlcTI6OnBsb3RNQShyZXMkZ3JvdXBfRGlmZjQ4aF9Eb3hwbHVzX3ZzX21pbnVzLCB5bGltPWMoLTIsMikpCiNwcmludChtYXBsb3QpCm1hcGxvdCA8LSBERVNlcTI6OnBsb3RNQShyZXMkZ3JvdXBfNDhoX0RveHBsdXNfdnNfbWludXMsIHlsaW09YygtNCw0KSwgbWFpbj0iNDhoX0RveHBsdXNfdnNfbWludXMiKQpwcmludChtYXBsb3QpCgpgYGAKCiMjIOWwpOW6puavlOaknOWumgoKIyMjRml0IG1vZGVsIExSVCAoQlJC44Go5ZCM44GY6Kit5a6aKQpBVEFD44Gu44OV44Kp44O844Oe44OD44OI44KS5oyB44Gj44Gm44GN44GfCgpgYGB7ciBkZXNlcTIgMn0KZGVmX2xpc3Rfc2VsZWN0IDwtIGRlZiAlPiUgbXV0YXRlKHRpbWU9ZmFjdG9yKHRpbWUsIGMoIlVJIiwiMGgiLCIyNGgiLCI0OGgiKSkpICU+JSBtdXRhdGUodHlwZT1mYWN0b3IodHlwZSwgYygiRG94TWludXMiLCJEb3hQbHVzIikpKQoKI2RlZl9saXN0X3NlbGVjdCA8LSBkZWYgJT4lIG11dGF0ZShncm93dGg9ZmFjdG9yKGdyb3d0aCwgYygiVUkiLCJEaWZmMGgiLCJEaWZmMjRoIiwiRGlmZjQ4aCIpKSkgJT4lIG11dGF0ZSh0eXBlPWZhY3Rvcih0eXBlLCBjKCJEb3htaW51cyIsIkRveHBsdXMiKSkpCgojZGVmX2xpc3Rfc2VsZWN0IDwtIGRlZgoKZGRzMCA8LSAwCmRkczFfMiA8LSAwCnJlczFfMiA8LSAwCgoKbW9kZWxfZnVsbCA8LSB+Z3Jvd3RoKnR5cGUgIyBCUkIKbW9kZWxfcmVkdWNlZCA8LSB+Z3Jvd3RoICMgQlJCCgojbW9kZWxfZnVsbCA8LSB+dGltZSp0eXBlICMgZnVsbCBtb2RlbCAgKH5ncm93dGgqdHlwZSAjIEJSQikKI21vZGVsX3JlZHVjZWQgPC0gfnRpbWUgIyByZWR1Y2VkIG1vZGVsICh+Z3Jvd3RoICMgQlJCKQoKY29sbmFtZXMoWCkgI+S9v+eUqOOBmeOCi+OCteODs+ODl+ODqwoKIyBmdWxsIG1vZGVsCmRkczBfTFJUIDwtIERFU2VxMjo6REVTZXFEYXRhU2V0RnJvbU1hdHJpeChYWyxkZWZfbGlzdF9zZWxlY3Qkc2FtcGxlXSxkZWZfbGlzdF9zZWxlY3QsbW9kZWxfZnVsbCkgICNmdWxsIG1vZGVsCgojIHJlZHVjZWQgbW9kZWwKZGRzX0xSVCA8LSBERVNlcTI6OkRFU2VxKGRkczBfTFJULCB0ZXN0PSJMUlQiLCByZWR1Y2VkPW1vZGVsX3JlZHVjZWQpICNyZWR1Y2VkIG1vZGVsCnJlc19MUlQgPC0gREVTZXEyOjpyZXN1bHRzKGRkc19MUlQpCnJlc19MUlRfZmRyMHAxIDwtIERFU2VxMjo6cmVzdWx0cyhkZHNfTFJUKSAgI+OCr+ODqeOCueOCv+ODquODs+OCsOOBq+S9v+eUqApyZXNfTFJUX2ZkcjBwMiA8LSBERVNlcTI6OnJlc3VsdHMoZGRzX0xSVCxhbHBoYT0wLjIpCgpwcmludChtb2RlbC5tYXRyaXgobW9kZWxfZnVsbCwgZGVmX2xpc3Rfc2VsZWN0KSkgI2Z1bGwgbW9kZWwKcHJpbnQobW9kZWwubWF0cml4KG1vZGVsX3JlZHVjZWQsIGRlZl9saXN0X3NlbGVjdCkpICNyZWR1Y2VkIG1vZGVsCgpoZWFkKHJlc19MUlRbb3JkZXIocmVzX0xSVCRwdmFsdWUpLCBdKQpERVNlcTI6OnN1bW1hcnkocmVzX0xSVF9mZHIwcDEpICMyMDE5MTEwOOS/ruatowpERVNlcTI6OnN1bW1hcnkocmVzX0xSVF9mZHIwcDIpICMyMDE5MTEwOOS/ruatowojREVTZXEyOjpzdW1tYXJ5LkRFU2VxUmVzdWx0cyhyZXNfTFJUX2ZkcjBwMSkKI0RFU2VxMjo6c3VtbWFyeS5ERVNlcVJlc3VsdHMocmVzX0xSVF9mZHIwcDIpCgpgYGAKCiMjIyDlsKTluqbmr5TmpJzlrpog57WQ5p6cCgojIyMjIHJlc3VsdCBMUlQKYGBge3IgcmVzdWx0IExSVH0KCmZvbGRlcl9uYW1lX3Bsb3RfcGF0aCA8LSAiLi9MUlQvIgpjc3ZmaWxlcGF0aCA8LSAiQlJCMDQzMmxhbmUybm91bWlfSDNtbTE4X0RveCIKCmFsbHJlc19MUlQgPC0gMAoKIy0tLS0tIOWFqOOBpuOBrue1kOaenCAtLS0tLSMKYWxscmVzX0xSVCA8LSBhc190aWJibGUocmVzX0xSVCxyb3duYW1lcz0iZW5zX2dlbmUiKSAlPiUgcmlnaHRfam9pbihlMmcsLikKZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9uYW1lX3Bsb3RfcGF0aCwgImFsbF9fIiwgY3N2ZmlsZXBhdGgsICJfbGFzdDIwMDgxMS5jc3YiLHNlcD0iIikKcmVhZHI6OndyaXRlX2NzdihhbGxyZXNfTFJULCBmaWxlX3BhdGgpICMg5YWo44Gm44Gu57WQ5p6cCgpucm93KGFsbHJlc19MUlQpCm5yb3coYWxscmVzX0xSVCAlPiUgZmlsdGVyKHBhZGo8MC4xKSkKbnJvdyhhbGxyZXNfTFJUICU+JSBmaWx0ZXIocGFkajwwLjIpKQoKIy0tLS0tIGZkciAwLjHjga7ntZDmnpwgLS0tLS0jCkxSVF9kZWdsaXN0X2ZkcjBwMSA8LSBhc190aWJibGUocmVzX0xSVF9mZHIwcDEscm93bmFtZXM9ImVuc19nZW5lIikgJT4lIHJpZ2h0X2pvaW4oZTJnLC4pICU+JSBmaWx0ZXIocGFkajwwLjEpICPjgq/jg6njgrnjgr/jg6rjg7PjgrDjgavkvb/nlKgKZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9uYW1lX3Bsb3RfcGF0aCwgIkRFR19mZHIwcDFfXyIsIGNzdmZpbGVwYXRoLCAiX2xhc3QyMDA4MTEuY3N2IixzZXA9IiIpICMg5LuK5Zue5Y+W5b6X44GX44GfREVH44Gu44Oq44K544OICnJlYWRyOjp3cml0ZV9jc3YoTFJUX2RlZ2xpc3RfZmRyMHAxLCBmaWxlX3BhdGgpICMg5YWo44Gm44Gu57WQ5p6cCm5yb3coTFJUX2RlZ2xpc3RfZmRyMHAxKQoKIy0tLS0tIGZkciAwLjLjga7ntZDmnpwgLS0tLS0jCkxSVF9kZWdsaXN0X2ZkcjBwMiA8LSBhc190aWJibGUocmVzX0xSVF9mZHIwcDIscm93bmFtZXM9ImVuc19nZW5lIikgJT4lIHJpZ2h0X2pvaW4oZTJnLC4pICU+JSBmaWx0ZXIocGFkajwwLjIpCmZpbGVfcGF0aCA8LSBwYXN0ZShmb2xkZXJfbmFtZV9wbG90X3BhdGgsICJERUdfZmRyMHAyX18iLCBjc3ZmaWxlcGF0aCwgIl9sYXN0MjAwODExLmNzdiIsc2VwPSIiKSAjIOS7iuWbnuWPluW+l+OBl+OBn0RFR+OBruODquOCueODiApyZWFkcjo6d3JpdGVfY3N2KExSVF9kZWdsaXN0X2ZkcjBwMiwgZmlsZV9wYXRoKSAjIOWFqOOBpuOBrue1kOaenApucm93KExSVF9kZWdsaXN0X2ZkcjBwMikKTFJUX2RlZ2xpc3RfZmRyMHAyIDwtIE5BCgojIEJSQuOBp+OBryByaWdodF9qb2luKGUyZywuKeOAgUFUQUPjgafjga8gcmlnaHRfam9pbihlbnNlbWJsZSwuKQoKYGBgCgojIyMjIENsdXN0ZXJpbmcgTFJUCgoKYGBge3IgY2x1c3RlcmluZyBmZHIgMHAxIGtlbWFuczR9CiMyMDE5MTIwNeS/ruato+OBqOS9nOaIkAoKIyDlhajjgabjga7jg4fjg7zjgr8KCiMtLSDkuIrjgaflrp/ooYwgLS0jCiNkZHNfTFJUIDwtIERFU2VxMjo6REVTZXEoZGRzMF9MUlQsIHRlc3Q9IkxSVCIsIHJlZHVjZWQ9bW9kZWxfcmVkdWNlZCkgI3JlZHVjZWQgbW9kZWwKI3Jlc19MUlQgPC0gREVTZXEyOjpyZXN1bHRzKGRkc19MUlQpCiNyZXNfTFJUX2ZkcjBwMSA8LSBERVNlcTI6OnJlc3VsdHMoZGRzX0xSVCkKI3Jlc19MUlRfZmRyMHAyIDwtIERFU2VxMjo6cmVzdWx0cyhkZHNfTFJULGFscGhhPTAuMikKIy0tLS0tLS0tLS0tLS0tIwoKI3ZzZF9MUlQgPC0gREVTZXEyOjp2c3QoZGRzX0xSVCkKCiNYZF9MUlQgPC0gU3VtbWFyaXplZEV4cGVyaW1lbnQ6OmFzc2F5KHZzZF9MUlQpW3doaWNoKHJlc19MUlRfZmRyMHAxJHBhZGo8MC4xKSxdICNkZWfjga7jg6rjgrnjg4ggI1hkIDwtIFN1bW1hcml6ZWRFeHBlcmltZW50Ojphc3NheSh2c2QpW3doaWNoKHJlcyRwYWRqPDAuMSksXQojWHNfTFJUIDwtIFhkX0xSVCAlPiUgdCAlPiUgc2NhbGUgJT4lIHQKCiMtLSDjgq/jg6njgrnjgr/jg6rjg7PjgrDjgavkvb/nlKjjgZfjgZ9YZCxYc+OCkuabuOOBjeWHuuOBlyAtLSMKIyAyMDE5MTIxMuS9nOaIkCAo44GC44Go44Gn56K66KqN44Gn44GN44KL44KI44GG44GrKQojIExSVF9kZWdsaXN0X2ZkcjBwMQoKI2ZpbGVfcGF0aCA8LSBwYXN0ZShmb2xkZXJfbmFtZV9wbG90X3BhdGgsICJjbHVzdGVyaW5nX3ZzZExSVGFsbF9fIiwgY3N2ZmlsZXBhdGgsICIuY3N2IixzZXA9IiIpIAojU3VtbWFyaXplZEV4cGVyaW1lbnQ6OmFzc2F5KHZzZF9MUlQpICU+JSBhc190aWJibGUocm93bmFtZXM9ImVuc19nZW5lIikgJT4lIHJlYWRyOjp3cml0ZV9jc3YoLixmaWxlX3BhdGgpCgojZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9uYW1lX3Bsb3RfcGF0aCwgImNsdXN0ZXJpbmdfWGRMUlRmZHIwcDFfXyIsIGNzdmZpbGVwYXRoLCAiLmNzdiIsc2VwPSIiKSAKI1hkX0xSVCAlPiUgYXNfdGliYmxlKHJvd25hbWVzPSJlbnNfZ2VuZSIpICU+JSByZWFkcjo6d3JpdGVfY3N2KC4sZmlsZV9wYXRoKSAKIyDjgZPjgozjgajlkIzjgZjvvJogU3VtbWFyaXplZEV4cGVyaW1lbnQ6OmFzc2F5KHZzZF9MUlQpICU+JSBhc190aWJibGUocm93bmFtZXM9ImVuc19nZW5lIikgICU+JSBmaWx0ZXIoZW5zX2dlbmUgJWluJSBMUlRfZGVnbGlzdF9mZHIwcDEkZW5zX2dlbmUpCgojLS0tLS0tLS0jCgojZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9uYW1lX3Bsb3RfcGF0aCwgImNsdXN0ZXJpbmdfWHNMUlRhbGxfXyIsIGNzdmZpbGVwYXRoLCAiLmNzdiIsc2VwPSIiKQojU3VtbWFyaXplZEV4cGVyaW1lbnQ6OmFzc2F5KHZzZF9MUlQpICU+JSB0ICU+JSBzY2FsZSAlPiUgdCAlPiUgYXNfdGliYmxlKHJvd25hbWVzPSJlbnNfZ2VuZSIpICU+JSByZWFkcjo6d3JpdGVfY3N2KC4sZmlsZV9wYXRoKQoKI2ZpbGVfcGF0aCA8LSBwYXN0ZShmb2xkZXJfbmFtZV9wbG90X3BhdGgsICJjbHVzdGVyaW5nX1hzTFJUZmRyMHAxX18iLCBjc3ZmaWxlcGF0aCwgIi5jc3YiLHNlcD0iIikgCiNYc19MUlQgJT4lIGFzX3RpYmJsZShyb3duYW1lcz0iZW5zX2dlbmUiKSAlPiUgcmVhZHI6OndyaXRlX2NzdiguLGZpbGVfcGF0aCkKIyDjgZPjgozjgajlkIzjgZjvvJogU3VtbWFyaXplZEV4cGVyaW1lbnQ6OmFzc2F5KHZzZF9MUlQpICU+JSB0ICU+JSBzY2FsZSAlPiUgdCAlPiUgYXNfdGliYmxlKHJvd25hbWVzPSJlbnNfZ2VuZSIpICU+JSBmaWx0ZXIoZW5zX2dlbmUgJWluJSBMUlRfZGVnbGlzdF9mZHIwcDEkZW5zX2dlbmUpCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCgoKenNjb3JlX3R5cGVfTFJUIDwtIHpzY29yZV90eXBlICU+JSBmaWx0ZXIoZW5zX2dlbmUgJWluJSBMUlRfZGVnbGlzdF9mZHIwcDEkZW5zX2dlbmUpCm5yb3coenNjb3JlX3R5cGVfTFJUKQoKWHNfTFJUIDwtIHpzY29yZV90eXBlX0xSVCAlPiUgZHBseXI6OnNlbGVjdCgtZW5zX2dlbmUsLWV4dF9nZW5lLCAtYmlvdHlwZSwtY2hyKSAlPiUgYXMubWF0cml4KCkKcm93bmFtZXMoWHNfTFJUKSA8LSB6c2NvcmVfdHlwZV9MUlQkZW5zX2dlbmUKCgoKIyMtLS0tLS0tLS0gY2x1c3RlcmluZyAtLS0tLS0tLS0tLSMKc2V0LnNlZWQoMykKCgprbV9MUlQgPC0ga21lYW5zKFhzX0xSVCw0LG5zdGFydCA9IDI1LGFsZ29yaXRobSA9ICJMbG95ZCIpCmttY19MUlQgPC0ga21fTFJUJGNlbnRlcnMgJT4lIGFzX3RpYmJsZShyb3duYW1lcz0iY2x1c3RlciIpICU+JSBnYXRoZXIoc2FtcGxlLHZhbCwtY2x1c3RlcikgJT4lIGlubmVyX2pvaW4oZGVmKQoKI2ttY19MUlRfZ3JvdXAgPC0ga21jX0xSVCAlPiUgbXV0YXRlKGdyb3d0aD1mYWN0b3IoZ3Jvd3RoLCBjKCJVSSIsIkRpZmYwaCIsIkRpZmYyNGgiLCJEaWZmNDhoIikpKSAlPiUgbXV0YXRlKHR5cGU9ZmFjdG9yKHR5cGUsIGMoIkRveHBsdXMiLCJEb3htaW51cyIpKSkKI2ttY19MUlRfZ3JvdXAgPC0ga21jX0xSVF9ncm91cCAlPiUgbXV0YXRlKHRpbWU9Y2FzZV93aGVuKGdyb3d0aD09IlVJIiB+IlVJIixncm93dGg9PSJEaWZmMGgifiIwaCIsZ3Jvd3RoPT0iRGlmZjI0aCJ+IjI0aCIsZ3Jvd3RoPT0iRGlmZjQ4aCJ+IjQ4aCIsVFJVRX4iZXJyb3IiKSkKI2ttY19MUlRfZ3JvdXAgPC0ga21jX0xSVF9ncm91cCAlPiUgbXV0YXRlKHRpbWU9ZmFjdG9yKHRpbWUsIGMoIlVJIiwiMGgiLCIyNGgiLCI0OGgiKSkpCgprbWNfTFJUX2dyb3VwIDwtIGttY19MUlQgJT4lIG11dGF0ZSh0aW1lPWZhY3Rvcih0aW1lLCBjKCJVSSIsICIwaCIsIjI0aCIsIjQ4aCIpKSkgJT4lIG11dGF0ZSh0eXBlPWZhY3Rvcih0eXBlLGMoIkRveFBsdXMiLCJEb3hNaW51cyIpKSkgJT4lIG11dGF0ZShyZXA9ZmFjdG9yKHJlcCwgYygiMSIsICIyIiwgIjMiLCAiNCIpKSkKCgpnZ2dnbGFiZWwgPC0gcGFzdGUoIjNUMyBEb3ggKy0sIGstbWVhbnMiLCJbMV0iLGttX0xSVCRzaXplWzFdLCJbMl0iLGttX0xSVCRzaXplWzJdLCJbM10iLGttX0xSVCRzaXplWzNdLCJbNF0iLGttX0xSVCRzaXplWzRdLHNlcD0iICIpCgoKIy0tLS0tLS0gc2l6ZSAtLS0tLS0tIwoKcHJpbnQoa21fTFJUJHNpemUpICAjNOOBpOOBruOCr+ODqeOCueOCv+ODvCBbMV0gNDcgNTUgOTQgMzMKCnJycmVzX0xSVCA8LSBrbV9MUlQkY2x1c3RlciAlPiUgdGliYmxlKGVuc19nZW5lPW5hbWVzKC4pLGNsdXN0ZXI9LikgJT4lIHJpZ2h0X2pvaW4oZTJnLC4pICU+JSBhcnJhbmdlKGNsdXN0ZXIpCgpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX25hbWVfcGxvdF9wYXRoLCAiREVHX2ZkcjBwMV9fIiwgY3N2ZmlsZXBhdGgsICJfa21lYW5zNF9fa21lYW5zX2NsdXN0ZXIuY3N2IixzZXA9IiIpIApyZWFkcjo6d3JpdGVfY3N2KHJycmVzX0xSVCxmaWxlX3BhdGgpCgojIy0tLS0tLS0gUENBIC0tLS0tLS0jCgpwY2FjbHVzdGVyX3NhdmUgPC0gcHJjb21wKFhzX0xSVCkkeCAlPiUgYXNfdGliYmxlICU+JSBzZWxlY3QoUEMxLFBDMikgJT4lIG11dGF0ZShjbHVzdGVyPWttX0xSVCRjbHVzdGVyKSAlPiUgZ2dwbG90KGFlcyhQQzEsUEMyLGNvbG91cj1mYWN0b3IoY2x1c3RlcikpKStnZW9tX3BvaW50KHNpemU9MS41LGFscGhhPTAuNikrY29vcmRfZml4ZWQoKSt0aGVtZV9saW5lZHJhdygpK2dnc2NpOjpzY2FsZV9jb2xvcl9kMygiY2F0ZWdvcnkyMCIpCgpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX25hbWVfcGxvdF9wYXRoLCAiREVHX2ZkcjBwMV9fIiwgY3N2ZmlsZXBhdGgsICJfa21lYW5zNF9fa21lYW5zX19wY2FjbHVzdGVyX1BDMVBDMi5wZGYiLHNlcD0iIikgCmdnc2F2ZShwbG90PXBjYWNsdXN0ZXJfc2F2ZSxmaWxlPWZpbGVfcGF0aCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgZHBpID0gMTIwKQpwcmludChwY2FjbHVzdGVyX3NhdmUpCgpwY2FjbHVzdGVyX3NhdmUgPC0gcHJjb21wKFhzX0xSVCkkeCAlPiUgYXNfdGliYmxlICU+JSBzZWxlY3QoUEMxLFBDMykgJT4lIG11dGF0ZShjbHVzdGVyPWttX0xSVCRjbHVzdGVyKSAlPiUgZ2dwbG90KGFlcyhQQzEsUEMzLGNvbG91cj1mYWN0b3IoY2x1c3RlcikpKStnZW9tX3BvaW50KHNpemU9MS41LGFscGhhPTAuNikrY29vcmRfZml4ZWQoKSt0aGVtZV9saW5lZHJhdygpK2dnc2NpOjpzY2FsZV9jb2xvcl9kMygiY2F0ZWdvcnkyMCIpCgpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX25hbWVfcGxvdF9wYXRoLCAiREVHX2ZkcjBwMV9fIiwgY3N2ZmlsZXBhdGgsICJfa21lYW5zNF9fa21lYW5zX19wY2FjbHVzdGVyX1BDMVBDMy5wZGYiLHNlcD0iIikgCmdnc2F2ZShwbG90PXBjYWNsdXN0ZXJfc2F2ZSxmaWxlPWZpbGVfcGF0aCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgZHBpID0gMTIwKQpwcmludChwY2FjbHVzdGVyX3NhdmUpCgoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBtb3VzZUNUWCAwNDM444KS5Y+C6ICD44Gr44CCCgojLS0tLS0tLS0tLS0tLS0tLS0tIwpmX2NsdXN0ZXIgPC0gZnVuY3Rpb24oeCkgeCAlPiUgZ3JvdXBfYnkoZ3JvdXAsIHR5cGUsIHRpbWUsIGNsdXN0ZXIpICU+JSBzdW1tYXJpc2UoYXZnPW1lYW4odmFsKSxzZT1zZCh2YWwpL3NxcnQobGVuZ3RoKHZhbCkpKSAlPiUgdW5ncm91cCgpCnByaW50KGttY19MUlRfZ3JvdXAgJT4lIGdyb3VwX2J5KGdyb3VwLCB0eXBlLCB0aW1lKSAlPiUgc3VtbWFyaXNlKCkpCgpmX2NsdXN0ZXJwIDwtIGZ1bmN0aW9uKHgpIHggJT4lIGdyb3VwX2J5KGdyb3VwLCB0eXBlLCB0aW1lLCBjbHVzdGVyKSAlPiUgc3VtbWFyaXNlKGF2Zz1tZWFuKHZhbCksc2U9c2QodmFsKS9zcXJ0KGxlbmd0aCh2YWwpKSkgJT4lIHVuZ3JvdXAoKQpwcmludChrbWNfTFJUX2dyb3VwICU+JSBncm91cF9ieShncm91cCwgdHlwZSwgdGltZSkgJT4lIHN1bW1hcmlzZSgpKSAj5L2c5Zuz55SoCgojLS0tLS0tLSMKCmNsdXN0ZXJfc2F2ZSA8LSBrbWNfTFJUX2dyb3VwICU+JQpnZ3Bsb3QoYWVzKHRpbWUsdmFsLGdyb3VwPXR5cGUsY29sb3VyPXR5cGUpKStnZW9tX2xpbmUoYWVzKHg9dGltZSx5PWF2Zyxjb2xvdXI9dHlwZSksZGF0YT1mX2NsdXN0ZXIpK2dlb21fcG9pbnQoKStmYWNldF93cmFwKH5jbHVzdGVyLDIpK2dnc2NpOjpzY2FsZV9jb2xvcl9ucGcoKSt0aGVtZV9taW5pbWFsKCkrIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSAgKyBnZ3RpdGxlKGdnZ2dsYWJlbCkKCmZpbGVfcGF0aCA8LSBwYXN0ZShmb2xkZXJfbmFtZV9wbG90X3BhdGgsICJERUdfZmRyMHAxX18iLCBjc3ZmaWxlcGF0aCwgIl9rbWVhbnM0X19jbHVzdGVyX3R5cGUucGRmIixzZXA9IiIpIApnZ3NhdmUocGxvdD1jbHVzdGVyX3NhdmUsZmlsZT1maWxlX3BhdGgsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNiwgZHBpID0gMTIwKQpwcmludChjbHVzdGVyX3NhdmUpCgojLS0tLS0tLSMKY2x1c3Rlcl9zYXZlIDwtIGttY19MUlRfZ3JvdXAgJT4lCmdncGxvdChhZXModGltZSx2YWwsZ3JvdXA9dHlwZSxjb2xvdXI9dHlwZSkpK2dlb21fcG9pbnQoKStmYWNldF93cmFwKH5jbHVzdGVyLDIpK2dnc2NpOjpzY2FsZV9jb2xvcl9ucGcoKSt0aGVtZV9taW5pbWFsKCkrIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSAgKyBnZ3RpdGxlKGdnZ2dsYWJlbCkKCgpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX25hbWVfcGxvdF9wYXRoLCAiREVHX2ZkcjBwMV9fIiwgY3N2ZmlsZXBhdGgsICJfa21lYW5zNF9fY2x1c3Rlcl90eXBlX25vbmxpbmUucGRmIixzZXA9IiIpIApnZ3NhdmUocGxvdD1jbHVzdGVyX3NhdmUsZmlsZT1maWxlX3BhdGgsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNiwgZHBpID0gMTIwKQojLS0tLS0tLS0tLS0tLS0tLS0tIwojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwoKCgojIy0tLS0tLS0tLSDjg6rjgrnjg4jjgpLkv53lrZggLS0tLS0tLS0tLS0tLSMKIyMgZGVn44Gu5oOF5aCx44KC5LuY44GR5Yqg44GI44KLICgyMDE5MTIwNCB2ZXIp44CCCgojLS0tLSBMUlTjga7mg4XloLEgYmFzZU1lYW7nrYnjgpLlj5bjgorlh7rjgZkgLS0tLSMKI0xSVF9kZWdsaXN0X2ZkcjBwMSA8LSBhc190aWJibGUocmVzX0xSVF9mZHIwcDEscm93bmFtZXM9ImVuc19nZW5lIikgJT4lIHJpZ2h0X2pvaW4oZTJnLC4pICU+JSBmaWx0ZXIocGFkajwwLjEpICPjgq/jg6njgrnjgr/jg6rjg7PjgrDjgavkvb/nlKgKI0xSVF9kZWdsaXN0X2ZkciA8LSBhc190aWJibGUocmVzX0xSVCxyb3duYW1lcz0iZW5zX2dlbmUiKSAlPiUgZmlsdGVyKHBhZGo8MC4xKQoKTFJUX2RlZ2xpc3RfZmRyIDwtIExSVF9kZWdsaXN0X2ZkcjBwMSAlPiUgc2VsZWN0KC0oZXh0X2dlbmUpLC0oYmlvdHlwZSksLShjaHIpKQpwcmludChmZHIpCm5yb3coTFJUX2RlZ2xpc3RfZmRyMHAxKQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwoKYXJyYW5nZV9ycnJlc19MUlQgPC0gcnJyZXNfTFJUICU+JSBhcnJhbmdlKGVuc19nZW5lKQpjbHVzdGVyX3Jlc0xSVF9mZHIgPC0gZnVsbF9qb2luKGFycmFuZ2VfcnJyZXNfTFJULCBMUlRfZGVnbGlzdF9mZHIsIGJ5PSJlbnNfZ2VuZSIpICU+JSBhcnJhbmdlKGNsdXN0ZXIpCm5yb3coY2x1c3Rlcl9yZXNMUlRfZmRyKQoKZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9uYW1lX3Bsb3RfcGF0aCwgIkRFR19mZHIwcDFfXyIsIGNzdmZpbGVwYXRoLCAiX2ttZWFuczRfX2NsdXN0ZXJfcmVzdWx0LmNzdiIsc2VwPSIiKQpyZWFkcjo6d3JpdGVfY3N2KGNsdXN0ZXJfcmVzTFJUX2ZkcixmaWxlX3BhdGgpCgojLS0g56K66KqNIC0tIwphcnJhbmdlX3JycmVzX0xSVCAlPiUgZmlsdGVyKGV4dF9nZW5lICVpbiUgYygiTXloMyIsIkNrbSIsIkFjdGExIiwiVG5udDIiLCJBY3RiIiwiQ3NycDMiLCJUcG0yIiwiTnNkaGwiKSkKIyMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCgpgYGAKCgoKCmBgYHtyIHBhcGVyIGZpZ30KIzIwMTkxMjA15L+u5q2j44CB5L2c5oiQCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBtb3VzZUNUWCAwNDM444KS5Y+C6ICD44Gr44CCCgojIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTI0LGZhY2U9Iml0YWxpYyIpCiMsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkgI1jou7jjga7jg6njg5njg6vjgpLlgr7jgZHjgovloLTlkIgKIywgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpICNY6Lu444Gu44Op44OZ44Or44KS5rC05bmz44Gr44GZ44KL5aC05ZCICgpjbHVzdGVyX3NhdmUgPC0ga21jX0xSVF9ncm91cCAlPiUgZ2dwbG90KGFlcyh0aW1lLHZhbCxncm91cD10eXBlLGNvbG91cj10eXBlKSkrZ2VvbV9saW5lKGFlcyh4PXRpbWUseT1hdmcsY29sb3VyPXR5cGUpLGRhdGE9Zl9jbHVzdGVycCkrZ2VvbV9wb2ludChzaXplPTIpK2ZhY2V0X3dyYXAofmNsdXN0ZXIsMSkgK3RoZW1lX2J3KCkgKyB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgc2l6ZT0yMCksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0yMCksYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MjQpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTApKSArZ2dzY2k6OnNjYWxlX2NvbG9yX25wZygpICsgZ2d0aXRsZShnZ2dnbGFiZWwpCgpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX25hbWVfcGxvdF9wYXRoLCAiREVHX2ZkcjBwMV9fIiwgY3N2ZmlsZXBhdGgsICJfa21lYW5zNF9fY2x1c3Rlcl90eXBlX19maW5hbC5wZGYiLHNlcD0iIikgCmdnc2F2ZShwbG90PWNsdXN0ZXJfc2F2ZSxmaWxlPWZpbGVfcGF0aCwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNiwgZHBpID0gMTIwKQpwcmludChjbHVzdGVyX3NhdmUpCiMtLS0tLS0tLS0tLS0tLS0tLS0jCgpjbHVzdGVyX3NhdmUgPC0ga21jX0xSVF9ncm91cCAlPiUgZ2dwbG90KGFlcyh0aW1lLHZhbCxncm91cD10eXBlLGNvbG91cj10eXBlKSkgKyBnZW9tX2FibGluZShpbnRlcmNlcHQ9MCxzbG9wZT0wLGxpbmV0eXBlPSJkYXNoZWQiLGNvbG91cj0iZ3JheSIpICsgZ2VvbV9saW5lKGFlcyh4PXRpbWUseT1hdmcsY29sb3VyPXR5cGUpLGRhdGE9Zl9jbHVzdGVycCkgKyBnZW9tX3BvaW50KHNpemU9MikrZmFjZXRfd3JhcCh+Y2x1c3RlciwxKSArdGhlbWVfYncoKSArIHRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPTIwKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTIwKSxheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0yMCksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjApLCBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0yNCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCkpICtnZ3NjaTo6c2NhbGVfY29sb3JfbnBnKCkgKyBnZ3RpdGxlKGdnZ2dsYWJlbCkKCgpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX25hbWVfcGxvdF9wYXRoLCAiREVHX2ZkcjBwMV9fIiwgY3N2ZmlsZXBhdGgsICJfa21lYW5zNF9fY2x1c3Rlcl90eXBlX19maW5hbF9kYXNoLnBkZiIsc2VwPSIiKSAKZ2dzYXZlKHBsb3Q9Y2x1c3Rlcl9zYXZlLGZpbGU9ZmlsZV9wYXRoLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA2LCBkcGkgPSAxMjApCnByaW50KGNsdXN0ZXJfc2F2ZSkKIy0tLS0tLS0tLS0tLS0tLS0tLSMKCmBgYAoKCiMjIyBUUE0gcGxvdAoKKENUWCBkYXk1IERFRyBVcCBEb3duIHZlcikKCiMjIyMgY2FsY3VsYXRlIFRQTQoKYGBge3IgVFBNIE1hdG9tZSBkZWYgMDcyMn0KIyAyMDE5IDEy5pyI5L+u5q2jCiMg44Kr44Km44Oz44OIMOOCguihqOekuuOBmeOCi+OCiOOBhuOBq+WkieabtCAoMjAxOTA3MjIpIEJSQi1zZXFfMDQzMmxhbmUyX1FDX3RtcGxfdjZyMTkwNzIyX25vdW1pX0gzbW0xOF9Eb3hfbGluZWFyXzA3MjIg44KI44KKCgp0cG0gPC0gdW1pICU+JSBncm91cF9ieShzYW1wbGUpICU+JSBtdXRhdGUoc2FtcGxlX3RvdGFsPXN1bShjb3VudCksVFBNPWNvdW50L3N1bShjb3VudCkqMWU2KSAlPiUgdW5ncm91cAp0cG1femVybyA8LSB0cG0gJT4lIHNlbGVjdChzYW1wbGUsZW5zX2dlbmUsVFBNKSAlPiUgc3ByZWFkKHNhbXBsZSxUUE0sZmlsbD0wKSAlPiUgZ2F0aGVyKHNhbXBsZSwgVFBNLCAtZW5zX2dlbmUpICPjgqvjgqbjg7Pjg4gw44Gu44K144Oz44OX44Or44GvMOOCkuWFpeOCjOOCiyAyMDE5MDcyMui/veWKoOOBl+OBpuS/ruatowoKdHBtX2RlZiA8LSBkZWYgJT4lIHNlbGVjdCgtY291bnQpICU+JSBkcGx5cjo6aW5uZXJfam9pbih0cG1femVybywgYnkgPSAic2FtcGxlIikgI3RwbeOCknRwbV96ZXJv44Gr5L+u5q2j44CBMjAxOTA3MjLkv67mraMKCiNmIDwtIGZ1bmN0aW9uKHgpIHggJT4lIGdyb3VwX2J5KGdyb3VwLHR5cGUsZ3Jvd3RoLGV4dF9nZW5lKSAlPiUgc3VtbWFyaXNlKGF2Zz1tZWFuKFRQTSksc2U9c2QoVFBNKS9zcXJ0KGxlbmd0aChUUE0pKSkgJT4lIHVuZ3JvdXAoKSAj6YeN6KaBKOW5s+Wdh+OCkuaxguOCgeOCi+OAgWdlb21fc21vb3RoKHNlPUZBTFNFKeOCkuS9v+OCj+OBquOBhHZlcikKCiMtLSDnorroqo0gLS0jCnVtaSAlPiUgZ3JvdXBfYnkoc2FtcGxlKSAlPiUgc3VtbWFyaXNlKHN1bShjb3VudCkpICMg56K66KqNCnRwbV96ZXJvICU+JSBncm91cF9ieShzYW1wbGUpICU+JSBzdW1tYXJpc2Uoc3VtKFRQTSkpICMg56K66KqNCgoKIy0tLS0tLS0tLSMKbWF0b21lIDwtIHRwbV9kZWYgJT4lIGlubmVyX2pvaW4oZTJnLCBieSA9ICJlbnNfZ2VuZSIpICMxOTEyMDMKCnJlYWRyOjp3cml0ZV9jc3YobWF0b21lLHBhc3RlKGNzdmZpbGVwYXRoLCAiX19UUE1fX2ZpbmFsMTkxMjA1X2xhc3QyMDA4MTEuY3N2IixzZXA9IiIpKSAjMTkxMjAzIOi/veWKoAoKI3JlYWRyOjp3cml0ZV9jc3YobWF0b21lLCJCUkIwNDM4bm91bWlfMTkwNTE1LUgzbW0xOEtPX0NUWF9TMi1EYXkwX1MzX2wyZmNfZmRyMHAydmVyX19UUE1fX2ZpbmFsMTkxMjA0LmNzdiIpICMxOTEyMDMg6L+95YqgCgoKYGBgCgoKIyMjIyBUUE0gZmlnCgrkvb/nlKjjgZnjgovjgoLjga7jgpLjg5fjg63jg4Pjg4ggKDE5MTIwM+S/ruatoykKCiJBY3RhMSIsIk15aDMiLCJDa20iLCJUbm50MiIsIkFjdGIiLCJDc3JwMyIKCmBgYHtyIFRQTSBmaWcgZXJyb3IgdmFyICYgYm94cGxvdCAxOTA3MjItMTIwMyBzZWxlY3Q3fQoKIz09PT09PT09IENoYW5nZSBldmVyeSBkYXRhIOOBk+OBk+OBp+mghueVquOCkuWkieabtCA9PT09PT09PSMKCiNtYXRvbWVfc2VsZWN0IDwtIG1hdG9tZSAlPiUgbXV0YXRlKGdyb3d0aD1mYWN0b3IoZ3Jvd3RoLCBjKCJVSSIsIkRpZmYwaCIsIkRpZmYyNGgiLCJEaWZmNDhoIikpKSAlPiUgbXV0YXRlKHR5cGU9ZmFjdG9yKHR5cGUsIGMoIkRveHBsdXMiLCJEb3htaW51cyIpKSkKI21hdG9tZV9zZWxlY3QgPC0gbWF0b21lX3NlbGVjdCAlPiUgbXV0YXRlKHRpbWU9Y2FzZV93aGVuKGdyb3d0aD09IlVJIiB+IlVJIixncm93dGg9PSJEaWZmMGgifiIwaCIsZ3Jvd3RoPT0iRGlmZjI0aCJ+IjI0aCIsZ3Jvd3RoPT0iRGlmZjQ4aCJ+IjQ4aCIsVFJVRX4iZXJyb3IiKSkKI21hdG9tZV9zZWxlY3QgPC0gbWF0b21lX3NlbGVjdCAlPiUgbXV0YXRlKHRpbWU9ZmFjdG9yKHRpbWUsIGMoIlVJIiwiMGgiLCIyNGgiLCI0OGgiKSkpCgptYXRvbWVfc2VsZWN0IDwtIG1hdG9tZSAlPiUgbXV0YXRlKHRpbWU9ZmFjdG9yKHRpbWUsIGMoIlVJIiwgIjBoIiwiMjRoIiwiNDhoIikpKSAlPiUgbXV0YXRlKHR5cGU9ZmFjdG9yKHR5cGUsYygiRG94UGx1cyIsIkRveE1pbnVzIikpKSAlPiUgbXV0YXRlKHJlcD1mYWN0b3IocmVwLCBjKCIxIiwgIjIiLCAiMyIsICI0IikpKQoKCiNtYXRvbWVfc2VsZWN0IDwtIG1hdG9tZSAlPiUgZmlsdGVyKGludGFjdF9DVFg9PSJDVFgifGludGFjdF9DVFg9PSJTS00iKSAlPiUgIG11dGF0ZShXVF9LTz1mYWN0b3IoV1RfS08sIGMoIkgzbW0xOEtPIiwiV1QiKSkpICU+JSBtdXRhdGUoRGF5PWZhY3RvcihEYXksIGMoIkRheTAiLCJEYXk1IiwiRGF5MTQiKSkpICU+JSBtdXRhdGUoaW50YWN0X0NUWD1mYWN0b3IoaW50YWN0X0NUWCwgYygiQ1RYIiwiU0tNIikpKQoKIy0tLS0tLS0jCgp0YmwgPC0gbWF0b21lX3NlbGVjdCAlPiUgZmlsdGVyKGV4dF9nZW5lICVpbiUgYygiTXloMyIsIkNrbSIsIkFjdGExIiwiVG5udDIiLCJBY3RiIiwiQ3NycDMiKSkKCiN0YmwyIDwtIG1hdG9tZV9zZWxlY3QgJT4lIGZpbHRlcihleHRfZ2VuZSAlaW4lIGMoIkFjdGExIiwiVHBtMiIpKQoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCgojZiA8LSBmdW5jdGlvbih4KSB4ICU+JSBncm91cF9ieShXVF9LTyxEYXksaW50YWN0X0NUWCxleHRfZ2VuZSkgJT4lIHN1bW1hcmlzZShhdmc9bWVhbihUUE0pLHNlPXNkKFRQTSkvc3FydChsZW5ndGgoVFBNKSkpICU+JSB1bmdyb3VwKCkgI+mHjeimgSAoQ1RY55So44Gr5aSJ5pu0KQoKZiA8LSBmdW5jdGlvbih4KSB4ICU+JSBncm91cF9ieShncm91cCwgdHlwZSwgdGltZSwgZXh0X2dlbmUpICU+JSBzdW1tYXJpc2UoYXZnPW1lYW4oVFBNKSxzZT1zZChUUE0pL3NxcnQobGVuZ3RoKFRQTSkpKSAlPiUgdW5ncm91cCgpCiMtLS0tIwp0YmwgJT4lIGdyb3VwX2J5KGdyb3VwLCB0eXBlLCB0aW1lKSAlPiUgc3VtbWFyaXplKCkKIy0tLS0jCgojZmFjZT0iaXRhbGljIgojLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpICNY6Lu444Gu44Op44OZ44Or44KS5YK+44GR44KL5aC05ZCICiMsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSAjWOi7uOOBruODqeODmeODq+OCkuawtOW5s+OBq+OBmeOCi+WgtOWQiAoKIyMjIHBvaW50ICMjIwpnZ2dnZ3BwIDwtICBnZ3Bsb3QodGJsLGFlcyh0aW1lLFRQTSxncm91cD10eXBlLGNvbG91cj10eXBlKSkrZ2VvbV9wb2ludChzaXplPTIpK2ZhY2V0X3dyYXAofmV4dF9nZW5lLHNjYWxlPSJmcmVlX3kiLDIpK2dlb21fbGluZShzaXplPTEuMCwgYWVzKHg9dGltZSx5PWF2Zyxjb2xvdXI9dHlwZSksZGF0YT1mKSt0aGVtZV9idygpICsgeWxpbSgwLE5BKSArIHRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPTE2KSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSxheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLCBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0yMCxmYWNlPSJpdGFsaWMiKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSkrZ2dzY2k6OnNjYWxlX2NvbG9yX25wZygpCgoKZmlsZV9wYXRoIDwtIHBhc3RlKCJUUE1fXyIsIGNzdmZpbGVwYXRoLCAiX193aXRoX3BvaW50X19maW5hbDE5MTIwNV9sYXN0MjAwODExLnBkZiIsc2VwPSIiKQpnZ3NhdmUoZmlsZT1maWxlX3BhdGgsIHBsb3QgPSBnZ2dnZ3BwLCBkcGkgPSAxMDAsIHdpZHRoID0gMTIsIGhlaWdodCA9IDEwKQoKI2dnc2F2ZShmaWxlPWZpbGVfcGF0aCwgcGxvdCA9IGdnZ2dncHApCiNnZ3NhdmUoZmlsZT0iVFBNX19CUkIwNDM4bm91bWlfSDNtbTE4S09fQ1RYX1MyLURheTBfUzNfX3dpdGhfcG9pbnRfX2ZpbmFsMTkxMjA0LnBkZiIsIHBsb3QgPSBnZ2dnZ3BwKQpwcmludChnZ2dnZ3BwKQoKZ2dnZ2dwcCA8LSAgZ2dwbG90KHRibCxhZXModGltZSxUUE0sZ3JvdXA9dHlwZSxjb2xvdXI9dHlwZSkpK2dlb21fcG9pbnQoc2l6ZT0yKStmYWNldF93cmFwKH5leHRfZ2VuZSxzY2FsZT0iZnJlZV95IiwyKStnZW9tX3Ntb290aChzZT1GQUxTRSkrdGhlbWVfYncoKSArIHlsaW0oMCxOQSkgKyB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgc2l6ZT0xNiksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNiksYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MjAsZmFjZT0iaXRhbGljIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNikpK2dnc2NpOjpzY2FsZV9jb2xvcl9ucGcoKQoKZmlsZV9wYXRoIDwtIHBhc3RlKCJUUE1fXyIsIGNzdmZpbGVwYXRoLCAiX193aXRoX3BvaW50X19maW5hbDE5MTIwNV9sYXN0MjAwODExX3Ntb290aC5wZGYiLHNlcD0iIikKZ2dzYXZlKGZpbGU9ZmlsZV9wYXRoLCBwbG90ID0gZ2dnZ2dwcCwgZHBpID0gMTAwLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMCkKCiNnZ3NhdmUoZmlsZT1maWxlX3BhdGgsIHBsb3QgPSBnZ2dnZ3BwKQojZ2dzYXZlKGZpbGU9IlRQTV9fQlJCMDQzOG5vdW1pX0gzbW0xOEtPX0NUWF9TMi1EYXkwX1MzX193aXRoX3BvaW50X19maW5hbDE5MTIwNF9zbW9vdGgucGRmIiwgcGxvdCA9IGdnZ2dncHApCiNwcmludChnZ2dnZ3BwKQoKCmBgYAoKIkFjdGExIiwiTXloMyIsIk5zZGhsIgoKYGBge3IgcGFwZXIgZmlnIFRQTSBzZWxlY3QyfQojMjAxOTEyMDQg5L2c5oiQCgp0YmwyIDwtIG1hdG9tZV9zZWxlY3QgJT4lIGZpbHRlcihleHRfZ2VuZSAlaW4lIGMoIkFjdGExIiwiTXloMyIsIk5zZGhsIikpCiMlPiUgbXV0YXRlKGV4dF9nZW5lPWZhY3RvcihleHRfZ2VuZSwgYygiQWN0YTEiLCJOc2RobCIsIk15aDMiKSkpCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyMgU0tN44KCQ1RY44Go5ZCM44GY6Imy44Gn6KGo56S6CgojIyMgcG9pbnQgIyMjCmdnZ2dncHAgPC0gIGdncGxvdCh0YmwyLGFlcyh0aW1lLFRQTSxncm91cD10eXBlLGNvbG91cj10eXBlKSkrZ2VvbV9wb2ludChzaXplPTIpK2ZhY2V0X3dyYXAofmV4dF9nZW5lLHNjYWxlPSJmcmVlX3kiKStnZW9tX2xpbmUoc2l6ZT0xLjAsIGFlcyh4PXRpbWUseT1hdmcsY29sb3VyPXR5cGUpLGRhdGE9ZikrdGhlbWVfYncoKSArIHlsaW0oMCxOQSkgKyB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgc2l6ZT0yMCksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0yMCksYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MjQsZmFjZT0iaXRhbGljIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0yMCkpICtnZ3NjaTo6c2NhbGVfY29sb3JfbnBnKCkgICsgZ2d0aXRsZSgiM1QzIERveCArLSIpCgpmaWxlX3BhdGggPC0gcGFzdGUoIlRQTV9fIiwgY3N2ZmlsZXBhdGgsICJfX3dpdGhfcG9pbnRfX0FjdGExX015aDNfTnNkaGxfX2ZpbmFsMTkxMjA1X2xhc3QyMDA4MTEucGRmIixzZXA9IiIpCmdnc2F2ZShmaWxlPWZpbGVfcGF0aCwgcGxvdCA9IGdnZ2dncHAsIGRwaSA9IDEwMCwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNikgIzLjgaTlm7Pjgarjgokgd2lkdGggPSA4CnByaW50KGdnZ2dncHApCgojZ2dzYXZlKGZpbGU9ZmlsZV9wYXRoLCBwbG90ID0gZ2dnZ2dwcCwgZHBpID0gMTAwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYpICMy44Gk5Zuz44Gq44KJIHdpZHRoID0gOAojZ2dzYXZlKGZpbGU9IlRQTV9fQlJCMDQzOG5vdW1pX0gzbW0xOEtPX0NUWF9TMi1EYXkwX1MzX193aXRoX3BvaW50X19BY3RhMV9UcG0yX19maW5hbDE5MTIwNC5wZGYiLCBwbG90ID0gZ2dnZ2dwcCwgZHBpID0gMTAwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYpCgoKYGBgCiJTbGMzOGEyIiwiSW5oYmEiLCJBY3RhMSIsIk15b2ciLCJNeWg5IiwiUnBsMTMiCgpgYGB7ciBwYXBlciBmaWcgVFBNIHNlbGVjdDMsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD01fQojMjAxOTEyMDQg5L2c5oiQCgpycnJlc19MUlQgJT4lIGZpbHRlcihleHRfZ2VuZSAlaW4lIGMoIlNsYzM4YTIiLCJJbmhiYSIsIkFjdGExIiwiTXlvZyIsIk15aDkiLCJScGwxMyIpKQoKbmJsMyA8LSBtYXRvbWVfc2VsZWN0ICU+JSBmaWx0ZXIoZXh0X2dlbmUgJWluJSBjKCJTbGMzOGEyIiwiSW5oYmEiLCJBY3RhMSIsIk15b2ciLCJNeWg5IiwiUnBsMTMiKSkgICU+JSBtdXRhdGUoZXh0X2dlbmU9ZmFjdG9yKGV4dF9nZW5lLGMoIlNsYzM4YTIiLCJJbmhiYSIsIkFjdGExIiwiTXlvZyIsIk15aDkiLCJScGwxMyIpKSkgCgoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMjIFNLTeOCgkNUWOOBqOWQjOOBmOiJsuOBp+ihqOekugoKIyMjIHBvaW50ICMjIwpnZ2dnZ3BwIDwtICBnZ3Bsb3QobmJsMyxhZXModGltZSxUUE0sZ3JvdXA9dHlwZSxjb2xvdXI9dHlwZSkpK2dlb21fcG9pbnQoc2l6ZT0yKStmYWNldF93cmFwKH5leHRfZ2VuZSxzY2FsZT0iZnJlZV95IikrZ2VvbV9saW5lKHNpemU9MS4wLCBhZXMoeD10aW1lLHk9YXZnLGNvbG91cj10eXBlKSxkYXRhPWYpK3RoZW1lX2J3KCkgKyB5bGltKDAsTkEpICsgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChoanVzdCA9IDEsIHNpemU9MjApLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTI0LGZhY2U9Iml0YWxpYyIpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApKSArZ2dzY2k6OnNjYWxlX2NvbG9yX25wZygpICArIGdndGl0bGUoIjNUMyBEb3ggKy0iKQoKZmlsZV9wYXRoIDwtIHBhc3RlKCJUUE1fXyIsIGNzdmZpbGVwYXRoLCAiX193aXRoX3BvaW50X19DbHVzdGVfUmVwX19maW5hbDE5MTIwNV9sYXN0MjAwODExLnBkZiIsc2VwPSIiKQpnZ3NhdmUoZmlsZT1maWxlX3BhdGgsIHBsb3QgPSBnZ2dnZ3BwLCBkcGkgPSAxMDAsIHdpZHRoID0gMTIsIGhlaWdodCA9IDYpICMy44Gk5Zuz44Gq44KJIHdpZHRoID0gOApwcmludChnZ2dnZ3BwKQoKI2dnc2F2ZShmaWxlPWZpbGVfcGF0aCwgcGxvdCA9IGdnZ2dncHAsIGRwaSA9IDEwMCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2KSAjMuOBpOWbs+OBquOCiSB3aWR0aCA9IDgKI2dnc2F2ZShmaWxlPSJUUE1fX0JSQjA0Mzhub3VtaV9IM21tMThLT19DVFhfUzItRGF5MF9TM19fd2l0aF9wb2ludF9fQWN0YTFfVHBtMl9fZmluYWwxOTEyMDQucGRmIiwgcGxvdCA9IGdnZ2dncHAsIGRwaSA9IDEwMCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2KQoKCmBgYAoKQUxMIERFRywgTFJUIEZEUiA8IDAuMQoKCmBgYHtyIE1hdG9tZSBUUE0gREVHZmlnIGNsdXN0ZXJ9CiMgREVH44KSY2x1c3RlcuOBq+WIhuOBkeOBpuihqOekuiAoMTkxMjA25L2c5oiQKQoKIy0tIOioreWumiAtLS0tLSMKcGxvdF90aXRsZTEgPC0gIlRQTSIKcGxvdF90aXRsZTIgPC0gIkRFRyAoTFJUKTogQlJCLXNlcSAzVDMgRG94ICstIgojZm9sZGVyX25hbWUgPC0gIkxSVCIKCiMtLSDjg5XjgqHjgqTjg6vlkI0g44Gu6Kit5a6aIC0tLSMKcGxvdF90aXRsZTAgPC0gcGFzdGUocGxvdF90aXRsZTEsIHBsb3RfdGl0bGUyLCBzZXA9IiwgIikKI2ZvbGRlcl9uYW1lX3Bsb3QwIDwtIHBhc3RlKCIuIixmb2xkZXJfbmFtZSwgcGxvdF90aXRsZTEsIiIsc2VwPSIvIikKI2ZvbGRlcl9uYW1lX3Bsb3RfcGF0aCA8LSBwYXN0ZShmb2xkZXJfbmFtZV9wbG90MCxwYXN0ZShmb2xkZXJfbmFtZSxwbG90X3RpdGxlMSwiIixzZXA9Il8iKSxzZXA9IiIpCgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCgojLS0tLS0g5LiK44Gn5Ye644Gm44GN44GfREVH44Gu44Oq44K544OI44Gu5Y+W44KK5Ye644GXIC0tLS0tIwpkZWdfY2x1c3Rlcl9saXN0IDwtIHJycmVzX0xSVCAgJT4lIGFycmFuZ2UoY2x1c3RlcikKZGVnX2NsdXN0ZXJfc2l6ZSA8LSBkZWdfY2x1c3Rlcl9saXN0ICU+JSBhcnJhbmdlKGVuc19nZW5lKSAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHN1bW1hcml6ZShzaXplPW4oKSkKCiMtLS0tLSBERUfjga7jgb/lj5bjgorlh7rjgZkgLS0tLS0tIwpkZWdfbWF0b21lIDwtIG1hdG9tZSAlPiUgZmlsdGVyKGVuc19nZW5lICVpbiUgZGVnX2NsdXN0ZXJfbGlzdCRlbnNfZ2VuZSkgJT4lIHJpZ2h0X2pvaW4oZGVnX2NsdXN0ZXJfbGlzdCAlPiUgc2VsZWN0KGVuc19nZW5lLGNsdXN0ZXIpLCBieSA9ICJlbnNfZ2VuZSIpCiNkZWdfbWF0b21lIDwtIGRlZ19tYXRvbWUgJT4lIG11dGF0ZShncm93dGg9ZmFjdG9yKGdyb3d0aCwgYygiVUkiLCJEaWZmMGgiLCJEaWZmMjRoIiwiRGlmZjQ4aCIpKSkgJT4lIG11dGF0ZSh0eXBlPWZhY3Rvcih0eXBlLCBjKCJEb3hwbHVzIiwiRG94bWludXMiKSkpCiNkZWdfbWF0b21lIDwtIGRlZ19tYXRvbWUgJT4lIG11dGF0ZSh0aW1lPWNhc2Vfd2hlbihncm93dGg9PSJVSSIgfiJVSSIsZ3Jvd3RoPT0iRGlmZjBoIn4iMGgiLGdyb3d0aD09IkRpZmYyNGgifiIyNGgiLGdyb3d0aD09IkRpZmY0OGgifiI0OGgiLFRSVUV+ImVycm9yIikpCiNkZWdfbWF0b21lIDwtIGRlZ19tYXRvbWUgJT4lIG11dGF0ZSh0aW1lPWZhY3Rvcih0aW1lLCBjKCJVSSIsIjBoIiwiMjRoIiwiNDhoIikpKQoKCmRlZ19tYXRvbWUgPC0gZGVnX21hdG9tZSAlPiUgbXV0YXRlKHRpbWU9ZmFjdG9yKHRpbWUsIGMoIlVJIiwgIjBoIiwiMjRoIiwiNDhoIikpKSAlPiUgbXV0YXRlKHR5cGU9ZmFjdG9yKHR5cGUsYygiRG94UGx1cyIsIkRveE1pbnVzIikpKSAlPiUgbXV0YXRlKHJlcD1mYWN0b3IocmVwLCBjKCIxIiwgIjIiLCAiMyIsICI0IikpKQoKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCgpmIDwtIGZ1bmN0aW9uKHgpIHggJT4lIGdyb3VwX2J5KGdyb3VwLCB0eXBlLCB0aW1lLCBleHRfZ2VuZSkgJT4lIHN1bW1hcmlzZShhdmc9bWVhbihUUE0pLHNlPXNkKFRQTSkvc3FydChsZW5ndGgoVFBNKSkpICU+JSB1bmdyb3VwKCkKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIyMgcG9pbnQgIyMjCiMjIOOCr+ODqeOCueOCv+ODvOOBlOOBqCAjIwpmb3IgKGkgaW4gMTo0KSB7CiAgY2x1c3Rlcl9ub3cgPC0gcGFzdGUoImNsdXN0ZXIiLGRlZ19jbHVzdGVyX3NpemUkY2x1c3RlcltpXSxzZXA9IiIpCiAgcGxvdF90aXRsZTBfY2x1c3RlciA8LSBwYXN0ZShwbG90X3RpdGxlMCwgY2x1c3Rlcl9ub3csIGRlZ19jbHVzdGVyX3NpemUkc2l6ZVtpXSwgc2VwPSIsICIpICPjgq/jg6njgrnjgr/jg7zjga7lgIvmlbDjgoLooajnpLooMjAxOTEwMjUpCiAgCiAgcHJpbnQocGxvdF90aXRsZTBfY2x1c3RlcikKICAKICBwcHBsb3RzaXplIDwtIChhcy5pbnRlZ2VyKGRlZ19jbHVzdGVyX3NpemUkc2l6ZVtpXS8xMCkgKyAxKSAqIDIgKyAxCiAgCiAgY2x1c3Rlcl9wbG90c2F2ZSA8LSBkZWdfbWF0b21lICU+JSBmaWx0ZXIoY2x1c3Rlcj09ZGVnX2NsdXN0ZXJfc2l6ZSRjbHVzdGVyW2ldKSAlPiUgIGdncGxvdChhZXModGltZSxUUE0sZ3JvdXA9dHlwZSxjb2xvdXI9dHlwZSkpK2dlb21fcG9pbnQoc2l6ZT0yKStmYWNldF93cmFwKH5leHRfZ2VuZSxzY2FsZT0iZnJlZV95IixuY29sPTEwKStnZW9tX2xpbmUoc2l6ZT0xLjAsIGFlcyh4PXRpbWUseT1hdmcsY29sb3VyPXR5cGUpLGRhdGE9ZikrdGhlbWVfYncoKSArIHlsaW0oMCxOQSkgKyB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgc2l6ZT0xNiksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTE4LGZhY2U9Iml0YWxpYyIpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpKSArZ2dzY2k6OnNjYWxlX2NvbG9yX25wZygpICsgZ2d0aXRsZShwbG90X3RpdGxlMF9jbHVzdGVyKQogIAogIAogIGZpbGVfcGF0aCA8LSBwYXN0ZShmb2xkZXJfbmFtZV9wbG90X3BhdGgsICJUUE1fXyIsIGNzdmZpbGVwYXRoLCAiX19MUlRERUdfZmRyMHAxX19maW5hbDE5MTIwNV9sYXN0MjAwODExXyIsY2x1c3Rlcl9ub3csIi5wZGYiLHNlcD0iIikgCiAgZ2dzYXZlKHBsb3Q9Y2x1c3Rlcl9wbG90c2F2ZSxmaWxlPWZpbGVfcGF0aCwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gcHBwbG90c2l6ZSwgZHBpID0gMTIwLCBsaW1pdHNpemUgPSBGQUxTRSkKCn0KCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIyMgcG9pbnQgIyMjCiMjIOOBvuOBqOOCgeOBpiAjIwoKIy0tIOaWnOOCgeOBruODqeODmeODqyAtLSMKCnBwcGxvdHNpemUgPC0gKGFzLmludGVnZXIobnJvdyhkZWdfY2x1c3Rlcl9saXN0KS8xMCkgKyAxKSAqIDIgKyAxCgpjbHVzdGVyX3Bsb3RzYXZlIDwtIGRlZ19tYXRvbWUgJT4lIGdncGxvdChhZXModGltZSxUUE0sZ3JvdXA9dHlwZSxjb2xvdXI9dHlwZSkpK2dlb21fcG9pbnQoc2l6ZT0yKStmYWNldF93cmFwKH5leHRfZ2VuZSxzY2FsZT0iZnJlZV95IixuY29sPTEwKStnZW9tX2xpbmUoc2l6ZT0xLjAsIGFlcyh4PXRpbWUseT1hdmcsY29sb3VyPXR5cGUpLGRhdGE9ZikrdGhlbWVfYncoKSArIHlsaW0oMCxOQSkgKyB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgc2l6ZT0xNiksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTE4LGZhY2U9Iml0YWxpYyIpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpKSArZ2dzY2k6OnNjYWxlX2NvbG9yX25wZygpICsgZ2d0aXRsZSgiM1QzIERveCArLSIpCgoKZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9uYW1lX3Bsb3RfcGF0aCwgIlRQTV9fIiwgY3N2ZmlsZXBhdGgsICJfX0xSVERFR19mZHIwcDFfX2ZpbmFsMTkxMjA1X2xhc3QyMDA4MTFfYWxsXzEucGRmIixzZXA9IiIpIApnZ3NhdmUocGxvdD1jbHVzdGVyX3Bsb3RzYXZlLGZpbGU9ZmlsZV9wYXRoLCB3aWR0aCA9IDIwLCBoZWlnaHQgPSBwcHBsb3RzaXplLCBkcGkgPSAzNjAsIGxpbWl0c2l6ZSA9IEZBTFNFKQoKIy0tIOaoquWQkeOBjeOBruODqeODmeODqyAtLSMKCnBwcGxvdHNpemUgPC0gcHBwbG90c2l6ZSAqIDEuMjUKCmNsdXN0ZXJfcGxvdHNhdmUgPC0gZGVnX21hdG9tZSAlPiUgZ2dwbG90KGFlcyh0aW1lLFRQTSxncm91cD10eXBlLGNvbG91cj10eXBlKSkrZ2VvbV9wb2ludChzaXplPTIpK2ZhY2V0X3dyYXAofmV4dF9nZW5lLHNjYWxlPSJmcmVlX3kiLG5jb2w9MTApK2dlb21fbGluZShzaXplPTEuMCwgYWVzKHg9dGltZSx5PWF2Zyxjb2xvdXI9dHlwZSksZGF0YT1mKSt0aGVtZV9idygpICsgeWxpbSgwLE5BKSArIHRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPTE2KSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSxheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLCBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xOCxmYWNlPSJpdGFsaWMiKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSkgK2dnc2NpOjpzY2FsZV9jb2xvcl9ucGcoKSArIGdndGl0bGUoIjNUMyBEb3ggKy0iKQoKZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9uYW1lX3Bsb3RfcGF0aCwgIlRQTV9fIiwgY3N2ZmlsZXBhdGgsICJfX0xSVERFR19mZHIwcDFfX2ZpbmFsMTkxMjA1X2xhc3QyMDA4MTFfYWxsXzIucGRmIixzZXA9IiIpIApnZ3NhdmUocGxvdD1jbHVzdGVyX3Bsb3RzYXZlLGZpbGU9ZmlsZV9wYXRoLCB3aWR0aCA9IDI1LCBoZWlnaHQgPSBwcHBsb3RzaXplLCBkcGkgPSAzNjAsIGxpbWl0c2l6ZSA9IEZBTFNFKQoKCiMtLW1lbW8tLSMKI2ZhY2U9Iml0YWxpYyIKIywgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSAjWOi7uOOBruODqeODmeODq+OCkuWCvuOBkeOCi+WgtOWQiAojLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkgI1jou7jjga7jg6njg5njg6vjgpLmsLTlubPjgavjgZnjgovloLTlkIgKCmBgYAoKVFBN5L2c5Zuz57WC5LqGCgoKIyMjIG5vcm1hbGl6ZWRjb3VudCBwbG90CgojIyMjIHNldCBub3JtQ291bnQgdGFibGUKCmBgYHtyIG5vcm1Db3VudCBNYXRvbWV9CiMgMjAxOSAxMuaciOS9nOaIkAoKbnJvdyhub3JtYWxpemVkY291bnQpCm5yb3cobm9ybWFsaXplZGNvdW50ICU+JSBpbm5lcl9qb2luKGUyZywgYnkgPSAiZW5zX2dlbmUiKSkKCiMtLS0tLS0tLS0jCm5vcm1fcGxvdGxpc3RfYWxsIDwtIG5vcm1hbGl6ZWRjb3VudCAlPiUgZ2F0aGVyKCJzYW1wbGUiLCAibm9ybWFsaXplZCIsLShlbnNfZ2VuZSkpICU+JSBpbm5lcl9qb2luKGRlZiwgYnkgPSAic2FtcGxlIikgJT4lIGlubmVyX2pvaW4oZTJnLCBieSA9ICJlbnNfZ2VuZSIpIAojbm9ybV9wbG90bGlzdF9hbGwgPC0gbm9ybV9wbG90bGlzdF9hbGwgJT4lIG11dGF0ZShncm93dGg9ZmFjdG9yKGdyb3d0aCwgYygiVUkiLCJEaWZmMGgiLCJEaWZmMjRoIiwiRGlmZjQ4aCIpKSkgJT4lIG11dGF0ZSh0eXBlPWZhY3Rvcih0eXBlLCBjKCJEb3hwbHVzIiwiRG94bWludXMiKSkpCiNub3JtX3Bsb3RsaXN0X2FsbCA8LSBub3JtX3Bsb3RsaXN0X2FsbCAlPiUgbXV0YXRlKHRpbWU9Y2FzZV93aGVuKGdyb3d0aD09IlVJIiB+IlVJIixncm93dGg9PSJEaWZmMGgifiIwaCIsZ3Jvd3RoPT0iRGlmZjI0aCJ+IjI0aCIsZ3Jvd3RoPT0iRGlmZjQ4aCJ+IjQ4aCIsVFJVRX4iZXJyb3IiKSkKI25vcm1fcGxvdGxpc3RfYWxsIDwtIG5vcm1fcGxvdGxpc3RfYWxsICU+JSBtdXRhdGUodGltZT1mYWN0b3IodGltZSwgYygiVUkiLCIwaCIsIjI0aCIsIjQ4aCIpKSkKCm5vcm1fcGxvdGxpc3RfYWxsIDwtIG5vcm1fcGxvdGxpc3RfYWxsICU+JSBtdXRhdGUodGltZT1mYWN0b3IodGltZSwgYygiVUkiLCAiMGgiLCIyNGgiLCI0OGgiKSkpICU+JSBtdXRhdGUodHlwZT1mYWN0b3IodHlwZSxjKCJEb3hQbHVzIiwiRG94TWludXMiKSkpICU+JSBtdXRhdGUocmVwPWZhY3RvcihyZXAsIGMoIjEiLCAiMiIsICIzIiwgIjQiKSkpCgpyZWFkcjo6d3JpdGVfY3N2KG5vcm1fcGxvdGxpc3RfYWxsLHBhc3RlKGNzdmZpbGVwYXRoLCAiX19ub3JtQ291bnRfX2ZpbmFsMTkxMjA1X2xhc3QyMDA4MTEuY3N2IixzZXA9IiIpKSAjMTkxMjA2IOi/veWKoAoKYGBgCgojIyMjIG5vcm1jb3VudCBmaWcKCkFMTCBERUcsIExSVCBGRFIgPCAwLjEgKFRvdGFsIDIyOSkKCmBgYHtyIHBsb3QgY2x1c3RlcmluZyBieSBCUkIgbm9ybWNvdW50fSAKIyAyMDE5MTIwNeS/ruato+OAgTIwMTkxMDI0CiMgREVH44KSY2x1c3RlcuOBq+WIhuOBkeOBpuihqOekuiAoMTkxMjA25L2c5oiQKQoKIy0tIOioreWumiAtLS0tLSMKcGxvdF90aXRsZTEgPC0gIm5vcm1Db3VudCIKcGxvdF90aXRsZTIgPC0gIkRFRyAoTFJUKTogQlJCLXNlcSAzVDMgRG94ICstIgojZm9sZGVyX25hbWUgPC0gIkxSVCIKCiMtLSDjg5XjgqHjgqTjg6vlkI0g44Gu6Kit5a6aIC0tLSMKcGxvdF90aXRsZTAgPC0gcGFzdGUocGxvdF90aXRsZTEsIHBsb3RfdGl0bGUyLCBzZXA9IiwgIikKI2ZvbGRlcl9uYW1lX3Bsb3QwIDwtIHBhc3RlKCIuIixmb2xkZXJfbmFtZSwgcGxvdF90aXRsZTEsIiIsc2VwPSIvIikKI2ZvbGRlcl9uYW1lX3Bsb3RfcGF0aCA8LSBwYXN0ZShmb2xkZXJfbmFtZV9wbG90MCxwYXN0ZShmb2xkZXJfbmFtZSxwbG90X3RpdGxlMSwiIixzZXA9Il8iKSxzZXA9IiIpCgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMjIG5vcm0gY291bnQg5b6M44Gu44OH44O844K/CgojLS0tLS0g5LiK44Gn5Ye644Gm44GN44GfREVH44Gu44Oq44K544OI44Gu5Y+W44KK5Ye644GXIC0tLS0tIwojLS0tLS0gREVH44Gu44G/5Y+W44KK5Ye644GZIC0tLS0tLSMKZGVnX25vcm1jb3VudCA8LSBub3JtX3Bsb3RsaXN0X2FsbCAlPiUgZmlsdGVyKGVuc19nZW5lICVpbiUgZGVnX2NsdXN0ZXJfbGlzdCRlbnNfZ2VuZSkgJT4lIHJpZ2h0X2pvaW4oZGVnX2NsdXN0ZXJfbGlzdCAlPiUgc2VsZWN0KGVuc19nZW5lLGNsdXN0ZXIpLCBieSA9ICJlbnNfZ2VuZSIpCiNkZWdfbm9ybWNvdW50IDwtIGRlZ19ub3JtY291bnQgJT4lIG11dGF0ZShncm93dGg9ZmFjdG9yKGdyb3d0aCwgYygiVUkiLCJEaWZmMGgiLCJEaWZmMjRoIiwiRGlmZjQ4aCIpKSkgJT4lIG11dGF0ZSh0eXBlPWZhY3Rvcih0eXBlLCBjKCJEb3hwbHVzIiwiRG94bWludXMiKSkpCiNkZWdfbm9ybWNvdW50IDwtIGRlZ19ub3JtY291bnQgJT4lIG11dGF0ZSh0aW1lPWNhc2Vfd2hlbihncm93dGg9PSJVSSIgfiJVSSIsZ3Jvd3RoPT0iRGlmZjBoIn4iMGgiLGdyb3d0aD09IkRpZmYyNGgifiIyNGgiLGdyb3d0aD09IkRpZmY0OGgifiI0OGgiLFRSVUV+ImVycm9yIikpCiNkZWdfbm9ybWNvdW50IDwtIGRlZ19ub3JtY291bnQgJT4lIG11dGF0ZSh0aW1lPWZhY3Rvcih0aW1lLCBjKCJVSSIsIjBoIiwiMjRoIiwiNDhoIikpKQoKI3Bsb3RsaXN0X2NsdXN0ZXIgPC0gZGVnX25vcm1jb3VudAojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwoKCmZfZ2VuZV9ub3JtIDwtIGZ1bmN0aW9uKHgpIHggJT4lIGdyb3VwX2J5KGdyb3VwLCB0eXBlLCB0aW1lLCBleHRfZ2VuZSkgJT4lIHN1bW1hcmlzZShhdmc9bWVhbihub3JtYWxpemVkKSxzZT1zZChub3JtYWxpemVkKS9zcXJ0KGxlbmd0aChub3JtYWxpemVkKSkpICU+JSB1bmdyb3VwKCkKI2YgPC0gZnVuY3Rpb24oeCkgeCAlPiUgZ3JvdXBfYnkoZ3JvdXAsIHR5cGUsIHRpbWUsIGV4dF9nZW5lKSAlPiUgc3VtbWFyaXNlKGF2Zz1tZWFuKFRQTSksc2U9c2QoVFBNKS9zcXJ0KGxlbmd0aChUUE0pKSkgJT4lIHVuZ3JvdXAoKQoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMjIyBwb2ludCAjIyMKIyMg44Kv44Op44K544K/44O844GU44GoICMjCmZvciAoaSBpbiAxOjQpIHsKICBjbHVzdGVyX25vdyA8LSBwYXN0ZSgiY2x1c3RlciIsZGVnX2NsdXN0ZXJfc2l6ZSRjbHVzdGVyW2ldLHNlcD0iIikKICBwbG90X3RpdGxlMF9jbHVzdGVyIDwtIHBhc3RlKHBsb3RfdGl0bGUwLCBjbHVzdGVyX25vdywgZGVnX2NsdXN0ZXJfc2l6ZSRzaXplW2ldLCBzZXA9IiwgIikgI+OCr+ODqeOCueOCv+ODvOOBruWAi+aVsOOCguihqOekuigyMDE5MTAyNSkKICAKICBwcmludChwbG90X3RpdGxlMF9jbHVzdGVyKQogIAogIHBwcGxvdHNpemUgPC0gKGFzLmludGVnZXIoZGVnX2NsdXN0ZXJfc2l6ZSRzaXplW2ldLzEwKSArIDEpICogMiArIDEKICAKICBjbHVzdGVyX3Bsb3RzYXZlIDwtIGRlZ19ub3JtY291bnQgJT4lIGZpbHRlcihjbHVzdGVyPT1kZWdfY2x1c3Rlcl9zaXplJGNsdXN0ZXJbaV0pICU+JSAgZ2dwbG90KGFlcyh0aW1lLG5vcm1hbGl6ZWQsZ3JvdXA9dHlwZSxjb2xvdXI9dHlwZSkpK2dlb21fcG9pbnQoc2l6ZT0yKStmYWNldF93cmFwKH5leHRfZ2VuZSxzY2FsZT0iZnJlZV95IixuY29sPTEwKStnZW9tX2xpbmUoc2l6ZT0xLjAsIGFlcyh4PXRpbWUseT1hdmcsY29sb3VyPXR5cGUpLGRhdGE9Zl9nZW5lX25vcm0pK3RoZW1lX2J3KCkgKyB5bGltKDAsTkEpICsgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChoanVzdCA9IDEsIHNpemU9MTYpLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLCBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSxheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLCBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xOCxmYWNlPSJpdGFsaWMiKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSkgK2dnc2NpOjpzY2FsZV9jb2xvcl9ucGcoKSArIGdndGl0bGUocGxvdF90aXRsZTBfY2x1c3RlcikgKyB5bGFiKCJub3JtYWxpemVkIGNvdW50IikgCiAgCiAgCiAgZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9uYW1lX3Bsb3RfcGF0aCwgIm5vcm1Db3VudF9fIiwgY3N2ZmlsZXBhdGgsICJfX0xSVERFR19mZHIwcDFfX2ZpbmFsMTkxMjA1X2xhc3QyMDA4MTFfIixjbHVzdGVyX25vdywiLnBkZiIsc2VwPSIiKSAKICBnZ3NhdmUocGxvdD1jbHVzdGVyX3Bsb3RzYXZlLGZpbGU9ZmlsZV9wYXRoLCB3aWR0aCA9IDIwLCBoZWlnaHQgPSBwcHBsb3RzaXplLCBkcGkgPSAxMjAsIGxpbWl0c2l6ZSA9IEZBTFNFKQoKfQoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMjIyBwb2ludCAjIyMKIyMg44G+44Go44KB44GmICMjCgojLS0g5pac44KB44Gu44Op44OZ44OrIC0tIwoKcHBwbG90c2l6ZSA8LSAoYXMuaW50ZWdlcihucm93KGRlZ19jbHVzdGVyX2xpc3QpLzEwKSArIDEpICogMiArIDEKCmNsdXN0ZXJfcGxvdHNhdmUgPC0gZGVnX25vcm1jb3VudCAlPiUgZ2dwbG90KGFlcyh0aW1lLG5vcm1hbGl6ZWQsZ3JvdXA9dHlwZSxjb2xvdXI9dHlwZSkpK2dlb21fcG9pbnQoc2l6ZT0yKStmYWNldF93cmFwKH5leHRfZ2VuZSxzY2FsZT0iZnJlZV95IixuY29sPTEwKStnZW9tX2xpbmUoc2l6ZT0xLjAsIGFlcyh4PXRpbWUseT1hdmcsY29sb3VyPXR5cGUpLGRhdGE9Zl9nZW5lX25vcm0pK3RoZW1lX2J3KCkgKyB5bGltKDAsTkEpICsgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChoanVzdCA9IDEsIHNpemU9MTYpLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLCBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSxheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLCBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xOCxmYWNlPSJpdGFsaWMiKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSkgK2dnc2NpOjpzY2FsZV9jb2xvcl9ucGcoKSArIGdndGl0bGUoIjNUMyBEb3ggKy0iKSArIHlsYWIoIm5vcm1hbGl6ZWQgY291bnQiKSAKCgpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX25hbWVfcGxvdF9wYXRoLCAibm9ybUNvdW50X18iLCBjc3ZmaWxlcGF0aCwgIl9fTFJUREVHX2ZkcjBwMV9fZmluYWwxOTEyMDVfbGFzdDIwMDgxMV9hbGxfMS5wZGYiLHNlcD0iIikgCmdnc2F2ZShwbG90PWNsdXN0ZXJfcGxvdHNhdmUsZmlsZT1maWxlX3BhdGgsIHdpZHRoID0gMjAsIGhlaWdodCA9IHBwcGxvdHNpemUsIGRwaSA9IDM2MCwgbGltaXRzaXplID0gRkFMU0UpCgojLS0g5qiq5ZCR44GN44Gu44Op44OZ44OrIC0tIwoKcHBwbG90c2l6ZSA8LSBwcHBsb3RzaXplICogMS4yNQoKY2x1c3Rlcl9wbG90c2F2ZSA8LSBkZWdfbm9ybWNvdW50ICU+JSBnZ3Bsb3QoYWVzKHRpbWUsbm9ybWFsaXplZCxncm91cD10eXBlLGNvbG91cj10eXBlKSkrZ2VvbV9wb2ludChzaXplPTIpK2ZhY2V0X3dyYXAofmV4dF9nZW5lLHNjYWxlPSJmcmVlX3kiLG5jb2w9MTApK2dlb21fbGluZShzaXplPTEuMCwgYWVzKHg9dGltZSx5PWF2Zyxjb2xvdXI9dHlwZSksZGF0YT1mX2dlbmVfbm9ybSkrdGhlbWVfYncoKSArIHlsaW0oMCxOQSkgKyB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgc2l6ZT0xNiksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNiksYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTgsZmFjZT0iaXRhbGljIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNikpICtnZ3NjaTo6c2NhbGVfY29sb3JfbnBnKCkgKyBnZ3RpdGxlKCIzVDMgRG94ICstIikgKyB5bGFiKCJub3JtYWxpemVkIGNvdW50IikgCgpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX25hbWVfcGxvdF9wYXRoLCAibm9ybUNvdW50X18iLCBjc3ZmaWxlcGF0aCwgIl9fTFJUREVHX2ZkcjBwMV9fZmluYWwxOTEyMDVfbGFzdDIwMDgxMV9hbGxfMi5wZGYiLHNlcD0iIikgCmdnc2F2ZShwbG90PWNsdXN0ZXJfcGxvdHNhdmUsZmlsZT1maWxlX3BhdGgsIHdpZHRoID0gMjUsIGhlaWdodCA9IHBwcGxvdHNpemUsIGRwaSA9IDM2MCwgbGltaXRzaXplID0gRkFMU0UpCgoKIy0tbWVtby0tIwojZmFjZT0iaXRhbGljIgojLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpICNY6Lu444Gu44Op44OZ44Or44KS5YK+44GR44KL5aC05ZCICiMsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSAjWOi7uOOBruODqeODmeODq+OCkuawtOW5s+OBq+OBmeOCi+WgtOWQiAoKCmBgYAoK5L2/55So44GZ44KL44KC44Gu44KS44OX44Ot44OD44OICgoiQWN0YTEiLCJNeWgzIiwiQ2ttIiwiVG5udDIiLCJBY3RiIiwiQ3NycDMiCgpgYGB7ciBub3JtY291bnQgZmlnIGVycm9yIHZhciAmIGJveHBsb3QgMTkwNzIyLTEyMDMgc2VsZWN0N30KCiM9PT09PT09PSBDaGFuZ2UgZXZlcnkgZGF0YSDjgZPjgZPjgafpoIbnlarjgpLlpInmm7QgPT09PT09PT0jCgojLS0tLS0tLSMKCm5ibCA8LSBub3JtX3Bsb3RsaXN0X2FsbCAlPiUgZmlsdGVyKGV4dF9nZW5lICVpbiUgYygiTXloMyIsIkNrbSIsIkFjdGExIiwiVG5udDIiLCJBY3RiIiwiQ3NycDMiKSkKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwoKI2ZfZ2VuZV9ub3JtIDwtIGZ1bmN0aW9uKHgpIHggJT4lIGdyb3VwX2J5KGdyb3VwLCB0eXBlLCB0aW1lLCBleHRfZ2VuZSkgJT4lIHN1bW1hcmlzZShhdmc9bWVhbihub3JtYWxpemVkKSxzZT1zZChub3JtYWxpemVkKS9zcXJ0KGxlbmd0aChub3JtYWxpemVkKSkpICU+JSB1bmdyb3VwKCkKCiMtLS0tIwpuYmwgJT4lIGdyb3VwX2J5KGdyb3VwLCB0eXBlLCB0aW1lKSAlPiUgc3VtbWFyaXplKCkKIy0tLS0jCgojZmFjZT0iaXRhbGljIgojLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpICNY6Lu444Gu44Op44OZ44Or44KS5YK+44GR44KL5aC05ZCICiMsIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSAjWOi7uOOBruODqeODmeODq+OCkuawtOW5s+OBq+OBmeOCi+WgtOWQiAoKIyMjIHBvaW50ICMjIwpnZ2dnZ3BwIDwtICBnZ3Bsb3QobmJsLGFlcyh0aW1lLG5vcm1hbGl6ZWQsZ3JvdXA9dHlwZSxjb2xvdXI9dHlwZSkpK2dlb21fcG9pbnQoc2l6ZT0yKStmYWNldF93cmFwKH5leHRfZ2VuZSxzY2FsZT0iZnJlZV95IiwyKStnZW9tX2xpbmUoc2l6ZT0xLjAsIGFlcyh4PXRpbWUseT1hdmcsY29sb3VyPXR5cGUpLGRhdGE9Zl9nZW5lX25vcm0pK3RoZW1lX2J3KCkgKyB5bGltKDAsTkEpICsgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChoanVzdCA9IDEsIHNpemU9MTYpLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTIwLGZhY2U9Iml0YWxpYyIpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpKStnZ3NjaTo6c2NhbGVfY29sb3JfbnBnKCkgICsgeWxhYigibm9ybWFsaXplZCBjb3VudCIpCgpmaWxlX3BhdGggPC0gcGFzdGUoIm5vcm1Db3VudF9fIiwgY3N2ZmlsZXBhdGgsICJfX3dpdGhfcG9pbnRfX2ZpbmFsMTkxMjA1X2xhc3QyMDA4MTEucGRmIixzZXA9IiIpCmdnc2F2ZShmaWxlPWZpbGVfcGF0aCwgcGxvdCA9IGdnZ2dncHAsIGRwaSA9IDEwMCwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTApCgpwcmludChnZ2dnZ3BwKQoKCmdnZ2dncHAgPC0gIGdncGxvdChuYmwsYWVzKHRpbWUsbm9ybWFsaXplZCxncm91cD10eXBlLGNvbG91cj10eXBlKSkrZ2VvbV9wb2ludChzaXplPTIpK2ZhY2V0X3dyYXAofmV4dF9nZW5lLHNjYWxlPSJmcmVlX3kiLDIpK2dlb21fc21vb3RoKHNlPUZBTFNFKSt0aGVtZV9idygpICsgeWxpbSgwLE5BKSArIHRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPTE2KSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSxheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNiksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLCBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0yMCxmYWNlPSJpdGFsaWMiKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE2KSkrZ2dzY2k6OnNjYWxlX2NvbG9yX25wZygpICArIHlsYWIoIm5vcm1hbGl6ZWQgY291bnQiKQoKZmlsZV9wYXRoIDwtIHBhc3RlKCJub3JtQ291bnRfXyIsIGNzdmZpbGVwYXRoLCAiX193aXRoX3BvaW50X19maW5hbDE5MTIwNV9sYXN0MjAwODExX3Ntb290aC5wZGYiLHNlcD0iIikKZ2dzYXZlKGZpbGU9ZmlsZV9wYXRoLCBwbG90ID0gZ2dnZ2dwcCwgZHBpID0gMTAwLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMCkKCgpgYGAKCiJBY3RhMSIsIk15aDMiLCJOc2RobCIKCmBgYHtyIHBhcGVyIGZpZyBub3JtY291bnQgc2VsZWN0Mn0KIzIwMTkxMjA0IOS9nOaIkAoKbmJsMiA8LSBub3JtX3Bsb3RsaXN0X2FsbCAlPiUgZmlsdGVyKGV4dF9nZW5lICVpbiUgYygiQWN0YTEiLCJNeWgzIiwiTnNkaGwiKSkKCiMlPiUgbXV0YXRlKGV4dF9nZW5lPWZhY3RvcihleHRfZ2VuZSwgYygiQWN0YTEiLCJOc2RobCIsIk15aDMiKSkpCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKCiMjIyBwb2ludCAjIyMKZ2dnZ2dwcCA8LSAgZ2dwbG90KG5ibDIsYWVzKHRpbWUsbm9ybWFsaXplZCxncm91cD10eXBlLGNvbG91cj10eXBlKSkrZ2VvbV9wb2ludChzaXplPTIpK2ZhY2V0X3dyYXAofmV4dF9nZW5lLHNjYWxlPSJmcmVlX3kiKStnZW9tX2xpbmUoc2l6ZT0xLjAsIGFlcyh4PXRpbWUseT1hdmcsY29sb3VyPXR5cGUpLGRhdGE9Zl9nZW5lX25vcm0pK3RoZW1lX2J3KCkgKyB5bGltKDAsTkEpICsgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChoanVzdCA9IDEsIHNpemU9MjApLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTI0LGZhY2U9Iml0YWxpYyIpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApKSArZ2dzY2k6OnNjYWxlX2NvbG9yX25wZygpICArIGdndGl0bGUoIjNUMyBEb3ggKy0iKSAgKyB5bGFiKCJub3JtYWxpemVkIGNvdW50IikKCmZpbGVfcGF0aCA8LSBwYXN0ZSgibm9ybUNvdW50X18iLCBjc3ZmaWxlcGF0aCwgIl9fd2l0aF9wb2ludF9fQWN0YTFfTXloM19Oc2RobF9fZmluYWwxOTEyMDVfbGFzdDIwMDgxMS5wZGYiLHNlcD0iIikKZ2dzYXZlKGZpbGU9ZmlsZV9wYXRoLCBwbG90ID0gZ2dnZ2dwcCwgZHBpID0gMTAwLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA2KSAjMuOBpOWbs+OBquOCiSB3aWR0aCA9IDgKcHJpbnQoZ2dnZ2dwcCkKCgpgYGAKCgpgYGB7ciBwYXBlciBmaWcgbm9ybWNvdW50IHNlbGVjdDMsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD01fQojMjAxOTEyMDQg5L2c5oiQCgpycnJlc19MUlQgJT4lIGZpbHRlcihleHRfZ2VuZSAlaW4lIGMoIlNsYzM4YTIiLCJJbmhiYSIsIkFjdGExIiwiTXlvZyIsIk15aDkiLCJScGwxMyIpKQoKbmJsMyA8LSBub3JtX3Bsb3RsaXN0X2FsbCAlPiUgZmlsdGVyKGV4dF9nZW5lICVpbiUgYygiU2xjMzhhMiIsIkluaGJhIiwiQWN0YTEiLCJNeW9nIiwiTXloOSIsIlJwbDEzIikpICAlPiUgbXV0YXRlKGV4dF9nZW5lPWZhY3RvcihleHRfZ2VuZSxjKCJTbGMzOGEyIiwiSW5oYmEiLCJBY3RhMSIsIk15b2ciLCJNeWg5IiwiUnBsMTMiKSkpIAoKIyU+JSBtdXRhdGUoZXh0X2dlbmU9ZmFjdG9yKGV4dF9nZW5lLCBjKCJBY3RhMSIsIk5zZGhsIiwiTXloMyIpKSkKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwoKIyMjIHBvaW50ICMjIwpnZ2dnZ3BwIDwtICBnZ3Bsb3QobmJsMyxhZXModGltZSxub3JtYWxpemVkLGdyb3VwPXR5cGUsY29sb3VyPXR5cGUpKStnZW9tX3BvaW50KHNpemU9MikrZmFjZXRfd3JhcCh+ZXh0X2dlbmUsc2NhbGU9ImZyZWVfeSIsbnJvdz0xKStnZW9tX2xpbmUoc2l6ZT0xLjAsIGFlcyh4PXRpbWUseT1hdmcsY29sb3VyPXR5cGUpLGRhdGE9Zl9nZW5lX25vcm0pK3RoZW1lX2J3KCkgKyB5bGltKDAsTkEpICsgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChoanVzdCA9IDEsIHNpemU9MjApLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApLGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTI0LGZhY2U9Iml0YWxpYyIpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApKSArZ2dzY2k6OnNjYWxlX2NvbG9yX25wZygpICArIGdndGl0bGUoIjNUMyBEb3ggKy0iKSAgKyB5bGFiKCJub3JtYWxpemVkIGNvdW50IikKCmZpbGVfcGF0aCA8LSBwYXN0ZSgibm9ybUNvdW50X18iLCBjc3ZmaWxlcGF0aCwgIl9fd2l0aF9wb2ludF9fQ2x1c3RlX1JlcF9fZmluYWwxOTEyMDVfbGFzdDIwMDgxMS5wZGYiLHNlcD0iIikKZ2dzYXZlKGZpbGU9ZmlsZV9wYXRoLCBwbG90ID0gZ2dnZ2dwcCwgZHBpID0gMTAwLCB3aWR0aCA9IDE2LCBoZWlnaHQgPSA1KSAjMuOBpOWbs+OBquOCiSB3aWR0aCA9IDgKcHJpbnQoZ2dnZ2dwcCkKCm5ibDMKYGBgCgrjgZPjgZPjgb7jgaflrp/ooYwKCgojIyMgR0/op6PmnpAgCgojIyMjICDjgq/jg6njgrnjgr/jg6rjg7PjgrAg44Gu57WQ5p6c44KSR08KMjAxOTEyMDbkv67mraMKCmBgYHtyIEdPIExvYWQgbGlzdCBwYXJ0Mi0xfQojMjAxOTEyMDbkv67mraMKCmZpbGVfcGF0aCA8LSBwYXN0ZShmb2xkZXJfbmFtZV9wbG90X3BhdGgsICJERUdfZmRyMHAxX18iLCBjc3ZmaWxlcGF0aCwgIl9rbWVhbnM0X19rbWVhbnNfY2x1c3Rlci5jc3YiLHNlcD0iIikgCnByaW50KGZpbGVfcGF0aCkKCmZpbGVfZGVnY2x1c3RlciA8LSBmaWxlX3BhdGgKCnRhYmxlX2RlZ2NsdXN0ZXIgPC0gcmVhZHI6OnJlYWRfY3N2KGZpbGVfZGVnY2x1c3RlcikgJT4lIGFycmFuZ2UoZW5zX2dlbmUpICU+JSBkcGx5cjo6c2VsZWN0KGVuc19nZW5lLGV4dF9nZW5lLGNsdXN0ZXIpCnRhYmxlX2RlZ2NsdXN0ZXIgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSBzdW1tYXJpc2Uoc2l6ZT1uKCkpCgojIyMjIyBGRFIgc2V0dGluZyAjIyMjIyMKZ29mZHIgPC0gMC4xCgpjbHVzdGVyX251bSA8LSA0CgpgYGAKCgpgYGB7ciBnbyBjbHVzdGVyUHJvZmlsZSBwYXJ0Mi0yfQojIDIwMTkxMjA25L+u5q2jCgpsaWJyYXJ5KGNsdXN0ZXJQcm9maWxlcikKbGlicmFyeShvcmcuTW0uZWcuZGIpCgpmb2xkZXJfcGF0aCA8LSAiLi9MUlQvY2x1c3RlclByb2ZpbGUvIgoKIy0tLS0tLS0tLS0tLS0jCmZpbGVfcGF0aCA8LSBwYXN0ZShmb2xkZXJfcGF0aCwgIkRFR19mZHIwcDFfXyIsIGNzdmZpbGVwYXRoLCAiX2ttZWFuc19CUGZkcjBwMV9nZW5lcmF0aW8iLHNlcD0iIikKZmlsZW5hbWVfY3N2IDwtIGZpbGVfcGF0aAoKZmlsZV9wYXRoIDwtIHBhc3RlKGZvbGRlcl9wYXRoLCAiREVHX2ZkcjBwMV9fIiwgY3N2ZmlsZXBhdGgsICJfa21lYW5zX0JQZmRyMHAxX2dlbmVyYXRpb19jbHVzdGVyIixzZXA9IiIpCmZpbGVuYW1lX2xpc3QgPC0gZmlsZV9wYXRoCgpwcmludChmaWxlbmFtZV9saXN0KQpwcmludChmaWxlbmFtZV9jc3YpCgoj5L6LIGZpbGVuYW1lX2xpc3QgPC0gIi4vTFJUL2NsdXN0ZXJQcm9maWxlL0gzbW0xOEtPX21vdXNlQ1RYX0JSQjA0MzhfZGF5NV8yZ3VuZmRyMHAyX2ttZWFuc19CUGZkcjBwMV9nZW5lcmF0aW9fY2x1c3RlciIKI+S+iyBmaWxlbmFtZV9jc3YgPC0gIi4vTFJUL2NsdXN0ZXJQcm9maWxlL0gzbW0xOEtPX21vdXNlQ1RYX0JSQjA0MzhfZGF5NV8yZ3VuZmRyMHAyX2tlbWFuc19CUGZkcjBwMV9nZW5lcmF0aW8iCiMtLS0tLS0tLS0tLS0tIwoKY2x1c3Rlcl9saXN0IDwtIGFzLmxpc3QoTkEpICPliJ3mnJ/ljJYKCmZvciAoaSBpbiAxOmNsdXN0ZXJfbnVtKSB7CiAgIHByZV9saXN0IDwtIGFzLmxpc3QoTkEpCiAgIHByZV9saXN0IDwtIHRhYmxlX2RlZ2NsdXN0ZXIgJT4lIGZpbHRlcihjbHVzdGVyPT1hcy5kb3VibGUoaSkpICU+JSBkcGx5cjo6c2VsZWN0KGVuc19nZW5lKSAlPiUgYXMubGlzdCgpCiAgIG5hbWVzKHByZV9saXN0KSA8LSBwYXN0ZSgiRU5TRU1CTCIsYXMuY2hhcmFjdGVyKGkpLHNlcD0iXyIpCiAKICAgaWYgKGkgPT0gMSkgeyAKICAgICBjbHVzdGVyX2xpc3QgPC0gcHJlX2xpc3QKICAgfSAKICAgZWxzZSBjbHVzdGVyX2xpc3QgPC0gYyhjbHVzdGVyX2xpc3QsIHByZV9saXN0KSAKfQoKCmZvciAoaSBpbiAxOmNsdXN0ZXJfbnVtKSB7CiAgIHByaW50KHBhc3RlKGksIGNsdXN0ZXJfbGlzdFtbaV1dICU+JSB0aWJibGU6OmVuZnJhbWUobmFtZSA9IE5VTEwpICU+JSBucm93KCksIHNlcD0iLCAiKSkKICAKICAgcHJlX2Vnb19CUCA8LSBlbnJpY2hHTyhnZW5lID0gY2x1c3Rlcl9saXN0W1tpXV0sCiAgICAgICAgICAgICAgICAgT3JnRGIgPSAib3JnLk1tLmVnLmRiIiwKICAgICAgICAgICAgICAgICBrZXlUeXBlID0gJ0VOU0VNQkwnLAogICAgICAgICAgICAgICAgIG9udCA9ICJCUCIsCiAgICAgICAgICAgICAgICAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgICAgICAgICAgICAgICAgcHZhbHVlQ3V0b2ZmICA9IGdvZmRyLCBxdmFsdWVDdXRvZmYgID0gMS4wKSAjMjAxOTEyMTHkv67mraMgIHB2YWx1ZUN1dG9mZiAgPSBmZHIKICAgCiAgICMjIHB2YWx1ZSA8IHF2YWx1ZSA8IHAuYWRqdXN0ICMjCiAgICMgcXZhbHVlQ3V0b2ZmICA9IDAuMyAgcXZhbHVlQ3V0b2ZmICA9IDAuMiAsIHF2YWx1ZUN1dG9mZiAgPSAxLjAKCiAgCiAgIGlmIChpID09IDEpIHsgCiAgICAgdGFibGVfZWdvX0JQIDwtIGRhdGEuZnJhbWUocHJlX2Vnb19CUCkgJT4lIG11dGF0ZShjbHVzdGVyPXBhc3RlKCJjbHVzdGVyIixhcy5jaGFyYWN0ZXIoaSksc2VwPSIiKSkgICMg44Oq44K544OI5Z6L44GL44KJ44OH44O844K/44OV44Os44O844Og44G45aSJ5o+bCiAgIH0gCiAgIGVsc2UgdGFibGVfZWdvX0JQIDwtIHRhYmxlX2Vnb19CUCAlPiUgYmluZF9yb3dzKGRhdGEuZnJhbWUocHJlX2Vnb19CUCkgJT4lIG11dGF0ZShjbHVzdGVyPXBhc3RlKCJjbHVzdGVyIixhcy5jaGFyYWN0ZXIoaSksc2VwPSIiKSkpCiAgIAogICAjLS0tLSBwbG90IC0tLSMKICAgQlBwbG90IDwtIGRvdHBsb3QocHJlX2Vnb19CUCwgc2hvd0NhdGVnb3J5PTMwLCBvcmRlckJ5ID0gIkNvdW50IikgI2NsdXN0ZXJQcm9maWxlIOOBruapn+iDveOBp+Wbs+OCkuaPj+OBjygxOTExMDbkv67mraMpIHdyb25nIG9yZGVyQnkgcGFyYW1ldGVyOyBzZXQgdG8gZGVmYXVsdCBgb3JkZXJCeSA9ICJ4ImAKICAgcHJpbnQoQlBwbG90KQogICBnZ3NhdmUoQlBwbG90LGZpbGU9cGFzdGUoZmlsZW5hbWVfbGlzdCxhcy5jaGFyYWN0ZXIoaSksIi5wbmciLHNlcD0iIiksIHdpZHRoID0gOCwgaGVpZ2h0ID0gMTIsIGRwaSA9IDEyMCkKICAgCiAgIEJQcGxvdCA8LSBkb3RwbG90KHByZV9lZ29fQlAsIHNob3dDYXRlZ29yeT0xMCwgb3JkZXJCeSA9ICJDb3VudCIpICNjbHVzdGVyUHJvZmlsZSDjga7mqZ/og73jgaflm7PjgpLmj4/jgY8oMTkxMTA25L+u5q2jKSB3cm9uZyBvcmRlckJ5IHBhcmFtZXRlcjsgc2V0IHRvIGRlZmF1bHQgYG9yZGVyQnkgPSAieCJgCiAgIHByaW50KEJQcGxvdCkKICAgZ2dzYXZlKEJQcGxvdCxmaWxlPXBhc3RlKGZpbGVuYW1lX2xpc3QsYXMuY2hhcmFjdGVyKGkpLCJfQ2F0ZWdvcnkxMC5wbmciLHNlcD0iIiksIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCwgZHBpID0gMTIwKQogICAKICAgQlBwbG90IDwtIGRvdHBsb3QocHJlX2Vnb19CUCwgc2hvd0NhdGVnb3J5PTUsIG9yZGVyQnkgPSAiQ291bnQiKSAjY2x1c3RlclByb2ZpbGUg44Gu5qmf6IO944Gn5Zuz44KS5o+P44GPKDE5MTEwNuS/ruatoykgd3Jvbmcgb3JkZXJCeSBwYXJhbWV0ZXI7IHNldCB0byBkZWZhdWx0IGBvcmRlckJ5ID0gIngiYAogICBwcmludChCUHBsb3QpCiAgIGdnc2F2ZShCUHBsb3QsZmlsZT1wYXN0ZShmaWxlbmFtZV9saXN0LGFzLmNoYXJhY3RlcihpKSwiX0NhdGVnb3J5NS5wbmciLHNlcD0iIiksIHdpZHRoID0gOCwgaGVpZ2h0ID0gMywgZHBpID0gMTIwKQp9CgpwcmludCh0YWJsZV9lZ29fQlAgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSBzdW1tYXJpemUoKSkKCiMtLS0tLS0jCiMg44OH44O844K/44GvdGFibGVfZWdvX0JQ44Gr44CCCgoKYGBgCgpgYGB7ciBnbyBjbHVzdGVyUHJvZmlsZSBwYXJ0Mi0zfQojIDIwMTkxMjA25L+u5q2jCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCiMg44OG44O844OW44Or44KS5L+d5a2YCiMgdGFibGVfZWdvX0JQXzN0M19MUlQyIDwtIHRhYmxlX2Vnb19CUAoKdGFibGVfZWdvX0JQMSA8LSB0YWJsZV9lZ29fQlAgJT4lIG11dGF0ZShjbHVzdGVyPWZhY3RvcihjbHVzdGVyLGMoImNsdXN0ZXIxIiwiY2x1c3RlcjIiLCJjbHVzdGVyMyIsImNsdXN0ZXI0IikpKSAlPiUgYXJyYW5nZShjbHVzdGVyLGRlc2MoQ291bnQpKSAjMTkxMTA2CgpyZWFkcjo6d3JpdGVfY3N2KHRhYmxlX2Vnb19CUDEscGFzdGUoZmlsZW5hbWVfY3N2LCIuY3N2IixzZXA9IiIpKQoKIyDlhYjjga7jg4bjg7zjg5bjg6vjga5nZW5lSUTjgpJnZW5lIG5hbWXjgavnva7mj5vjgZnjgovjgIIoMjAxOTEwMjUpCgp0YWJsZWdvIDwtIHRhYmxlX2Vnb19CUDEgJT4lIG11dGF0ZShnZW5lX25hbWU9Z2VuZUlEKSAlPiUgZHBseXI6OnNlbGVjdCgtKHF2YWx1ZSkpCgpmb3IgKGkgaW4gMTpucm93KHRhYmxlX2RlZ2NsdXN0ZXIpKSB7CiAgdGFibGVnbyA8LSB0YWJsZWdvICU+JSBtdXRhdGUoZ2VuZV9uYW1lPWdzdWIoZ2VuZV9uYW1lLCBwYXR0ZXJuPXRhYmxlX2RlZ2NsdXN0ZXIkZW5zX2dlbmVbaV0sIHJlcGxhY2VtZW50PXRhYmxlX2RlZ2NsdXN0ZXIkZXh0X2dlbmVbaV0sIGlnbm9yZS5jYXNlID0gVFJVRSkpCn0KCnByaW50KHRhYmxlZ28pCgpyZWFkcjo6d3JpdGVfY3N2KHRhYmxlZ28scGFzdGUoZmlsZW5hbWVfY3N2LCJfZ2VuZW5hbWUuY3N2IixzZXA9IiIpKQoKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKCiNHT+OBrnRlcm3jga7mlbAKcHJpbnQodGFibGVnbyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHN1bW1hcml6ZShjbHVzdGVyXzN0M0RveF9udW0gPSBkcGx5cjo6bigpKSkKCiMjIOWkieabtCAjIwp0YWJsZV9lZ29fQlBfMmd1bmZkcjBwMl9jbHVzdGVyIDwtIHRhYmxlZ28KCiMtLS0g44Oh44OiIC0tLS0jCiN0YWJsZWdnZyA8LSB0YWJsZV9lZ29fY2x1c3RlcmNsdXN0ZXIKI2NvbG0gPC0gdGFibGVnZ2ckZ2VuZUlECiNmb3IgKGkgaW4gMTo4OCkgewojICBjb2xtIDwtIHN1YihycnJlc19jbHVzdGVyMyRlbnNfZ2VuZVtpXSwgcnJyZXNfY2x1c3RlcjMkZXh0X2dlbmVbaV0sIGNvbG0pCiN9CiNwcmludChjb2xtKQoKYGBgCgpgYGB7ciBjbHVzdGVyUHJvZmlsZSBwYXJ0Mi00fQojIDIwMTkxMjA2LCAxOTEyMTHkv67mraMKIyBCZW5qYW1pbmkgY29ycmVjdGlvbiDjgpIgcC1hZGp1c3Qg44Go44GX44Gm5L2/55So44GZ44KLCgpmaWxlX3BhdGggPC0gcGFzdGUoZm9sZGVyX3BhdGgsICJERUdfZmRyMHAxX18iLCBjc3ZmaWxlcGF0aCwgIl9rbWVhbnNfQlBmZHIwcDEucGRmIixzZXA9IiIpCmZpbGVfQlBfcGxvdCA8LSBmaWxlX3BhdGgKCmZpbGVfcGF0aCA8LSBwYXN0ZShmb2xkZXJfcGF0aCwgIkRFR19mZHIwcDFfXyIsIGNzdmZpbGVwYXRoLCAiX2ttZWFuc19fQlBmZHIwcDFfbXVzY2xlb25seS5wZGYiLHNlcD0iIikKZmlsZV9CUF9wbG90X211c2NsZSA8LSBmaWxlX3BhdGgKCnByaW50KGZpbGVfQlBfcGxvdCkKcHJpbnQoZmlsZV9CUF9wbG90X211c2NsZSkKCiMg5L6LIGZpbGVfQlBfcGxvdCA8LSAiLi8yZ3VuL2NsdXN0ZXJQcm9maWxlL0JQZmRyMHAxX19IM21tMThLT19tb3VzZUNUWF9CUkIwNDM4X2RheTVfMmd1bmZkcjBwMl9rbWVhbnMucGRmIgojIOS+iyBmaWxlX0JQX3Bsb3RfbXVzY2xlIDwtICIuLzJndW4vY2x1c3RlclByb2ZpbGUvQlBmZHIwcDFfX0gzbW0xOEtPX21vdXNlQ1RYX0JSQjA0MzhfZGF5NV8yZ3VuZmRyMHAyX2ttZWFuc19tdXNjbGVvbmx5LnBkZiIKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLSMKCkJQX21hdG9tZSA8LSB0YWJsZWdvCgpyb3dsZW5ndGggPC0gQlBfbWF0b21lICU+JSBncm91cF9ieShEZXNjcmlwdGlvbikgJT4lIHN1bW1hcml6ZSgpICU+JSBucm93KCkKQlBfcGxvdCA8LSBCUF9tYXRvbWUgJT4lIGZpbHRlcihwLmFkanVzdDxnb2ZkcikgJT4lIGdncGxvdChhZXMoeD1jbHVzdGVyLCB5PXJlb3JkZXIoRGVzY3JpcHRpb24sQ291bnQpLCBzaXplPUNvdW50LCBmaWxsPXAuYWRqdXN0KSkgKyBnZW9tX3BvaW50KHNoYXBlID0gMjEpICsgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArIHRoZW1lX21pbmltYWwoKSArIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSxheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gInJlZCIgLCBoaWdoID0gImJsdWUiKSsgeGxhYigiM1QzIERveCArLSIpICsgeWxhYigiR08gRGVzY3JpcHRpb24gKEJQKSIpICsgbGFicyhmaWxsPXBhc3RlKCJwLmFkanVzdCAoQkgpIDwgIixhcy5jaGFyYWN0ZXIoZ29mZHIpLHNlcD0iIikpCnByaW50KEJQX3Bsb3QpCmdnc2F2ZShwbG90PUJQX3Bsb3QsZmlsZT1maWxlX0JQX3Bsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9ICg1K3Jvd2xlbmd0aC82KSwgZHBpID0gMTIwLGxpbWl0c2l6ZSA9IEZBTFNFKQoKIy0tLW11c2NsZemWoumAo+OBruOBvwpCUF9tYXRvbWVfbXVzY2xlIDwtIEJQX21hdG9tZSAlPiUgZmlsdGVyKGdyZXBsKCJtdXNjbGUiLCBEZXNjcmlwdGlvbil8Z3JlcGwoIm15byIsIERlc2NyaXB0aW9uKSkKcm93bGVuZ3RoIDwtIEJQX21hdG9tZV9tdXNjbGUgJT4lIGdyb3VwX2J5KERlc2NyaXB0aW9uKSAlPiUgc3VtbWFyaXplKCkgJT4lIG5yb3coKQpCUF9wbG90X211c2NsZSA8LSBCUF9tYXRvbWVfbXVzY2xlICU+JSBmaWx0ZXIocC5hZGp1c3Q8Z29mZHIpICU+JSBnZ3Bsb3QoYWVzKHg9Y2x1c3RlciwgeT1yZW9yZGVyKERlc2NyaXB0aW9uLENvdW50KSwgc2l6ZT1Db3VudCwgZmlsbD1wLmFkanVzdCkpICsgZ2VvbV9wb2ludChzaGFwZSA9IDIxKSArIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKyB0aGVtZV9taW5pbWFsKCkgKyB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJyZWQiICwgaGlnaCA9ICJibHVlIikgKyB4bGFiKCIzVDMgRG94ICstIChtdXNjbGUpIikgKyB5bGFiKCJHTyBEZXNjcmlwdGlvbiAoQlApIikgKyBsYWJzKGZpbGw9cGFzdGUoInAuYWRqdXN0IChCSCkgPCAiLGFzLmNoYXJhY3Rlcihnb2Zkciksc2VwPSIiKSkKcHJpbnQoQlBfcGxvdF9tdXNjbGUpCmdnc2F2ZShCUF9wbG90X211c2NsZSxmaWxlPWZpbGVfQlBfcGxvdF9tdXNjbGUsIHdpZHRoID0gOCwgaGVpZ2h0ID0gKDUrcm93bGVuZ3RoLzYpLCBkcGkgPSAxMjAsbGltaXRzaXplID0gRkFMU0UpCgoKYGBgCgoKYGBge3Igd2l0ZSByZXN1bHQgdGFibGUgY2x1c3RlclByb2ZpbGUgcGFydDItNX0KIyAyMDE5MTIwNuS/ruatowojIDIwMTkxMDAz6L+95YqgLCAxOTExMjDlpInmm7QKCiMtLS0tLSBjb3VudOOBruOBv+OBrnRhYmxlIC0tLS0tLS0tLS0tLS0tIwphYWFfdGFibGVnbyA8LSB0YWJsZWdvICU+JSBkcGx5cjo6c2VsZWN0KElELERlc2NyaXB0aW9uLGNsdXN0ZXIsQ291bnQpICU+JSBzcHJlYWQoa2V5PWNsdXN0ZXIsdmFsdWUgPSBDb3VudCxmaWxsPTApICU+JSBtdXRhdGUoVG90YWw9IGNsdXN0ZXIyICsgY2x1c3RlcjMgK2NsdXN0ZXI0KSAgJT4lIGFycmFuZ2UoZGVzYyhUb3RhbCkpCgojYWFhX3RhYmxlZ28gPC0gdGFibGVnbyAlPiUgZHBseXI6OnNlbGVjdChJRCxEZXNjcmlwdGlvbixjbHVzdGVyLENvdW50KSAlPiUgc3ByZWFkKGtleT1jbHVzdGVyLHZhbHVlID0gQ291bnQsZmlsbD0wKSAlPiUgbXV0YXRlKFRvdGFsPSBjbHVzdGVyMSArY2x1c3RlcjIgKyBjbHVzdGVyMyArY2x1c3RlcjQpICAlPiUgYXJyYW5nZShkZXNjKFRvdGFsKSkKCmZpbGVfcGF0aCA8LSBwYXN0ZShmb2xkZXJfcGF0aCwgIkRFR19mZHIwcDFfXyIsIGNzdmZpbGVwYXRoLCAiX2ttZWFuc19fQlBmZHIwcDFfX2NvdW50X3RhYmxlLmNzdiIsc2VwPSIiKQpwcmludChmaWxlX3BhdGgpCnJlYWRyOjp3cml0ZV9jc3YoYWFhX3RhYmxlZ28sZmlsZV9wYXRoKQoKI+S+iyAiLi8yZ3VuL2NsdXN0ZXJQcm9maWxlL0JQZmRyMHAxX19IM21tS09fbW91c2VDVFhfQlJCMDQzOF8yZ3VuZmRyMHAyX2tlbWFuc19fY291bnRfdGFibGUuY3N2IgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKCmBgYAoKYGBge1IgbWVtbyBwYXJ0Mi02fQojIHg9cHZhbHVlLCB5PXAuYWRqdXN0CnBsb3R0dCA8LSB0YWJsZV9lZ29fQlAgJT4lIGdncGxvdChhZXMoeD1wdmFsdWUsIHk9cC5hZGp1c3QsIHNpemU9Q291bnQpKSArIGdlb21fcG9pbnQoKStnZW9tX2FibGluZShpbnRlcmNlcHQ9MCxzbG9wZT0xLjAsbGluZXR5cGU9ImRhc2hlZCIsY29sb3VyPSJibHVlIikgKyB4bGltKDAsTkEpICsgeWxpbSgwLE5BKSArIGdndGl0bGUobGFiZWw9cGFzdGUoInAuYWRqdXN0IChCSCkgPCAiLGFzLmNoYXJhY3Rlcihnb2Zkciksc2VwPSIiKSkKcHJpbnQocGxvdHR0KQoKIyB4PXB2YWx1ZSwgeT1xdmFsdWUKcGxvdHR0IDwtIHRhYmxlX2Vnb19CUCAlPiUgZ2dwbG90KGFlcyh4PXB2YWx1ZSwgeT1xdmFsdWUsIHNpemU9Q291bnQpKSArIGdlb21fcG9pbnQoKStnZW9tX2FibGluZShpbnRlcmNlcHQ9MCxzbG9wZT0xLjAsbGluZXR5cGU9ImRhc2hlZCIsY29sb3VyPSJibHVlIikgKyB4bGltKDAsTkEpICsgeWxpbSgwLE5BKSArIGdndGl0bGUobGFiZWw9cGFzdGUoInAuYWRqdXN0IChCSCkgPCAiLGFzLmNoYXJhY3Rlcihnb2Zkciksc2VwPSIiKSkKcHJpbnQocGxvdHR0KQoKIyB4PXAuYWRqdXN0LCB5PXF2YWx1ZQpwbG90dHQgPC0gdGFibGVfZWdvX0JQICU+JSBnZ3Bsb3QoYWVzKHg9cC5hZGp1c3QsIHk9cXZhbHVlLCBzaXplPUNvdW50KSkgKyBnZW9tX3BvaW50KCkrZ2VvbV9hYmxpbmUoaW50ZXJjZXB0PTAsc2xvcGU9MS4wLGxpbmV0eXBlPSJkYXNoZWQiLGNvbG91cj0iYmx1ZSIpICsgeGxpbSgwLE5BKSArIHlsaW0oMCxOQSkgKyBnZ3RpdGxlKGxhYmVsPXBhc3RlKCJwLmFkanVzdCAoQkgpIDwgIixhcy5jaGFyYWN0ZXIoZ29mZHIpLHNlcD0iIikpCnByaW50KHBsb3R0dCkKCgojIyBwdmFsdWUgPCBxdmFsdWUgPCBwLmFkanVzdCAjIwojIHB2YWx1ZSA8IHAuYWRqdXN0CiMgcHZhbHVlIDwgcXZhbHVlCiMgcXZhbHVlIDwgcC5hZGp1c3QKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0jCgojW0JCUkItc2VxXzA0MzhfUUNfdG1wbF92Nl9ub3VtaV8xOTA1MTUtSDNtbTE4S09fQ1RYX1MyLURheTBfUzNfZmRyMHAydmVyX2FuZF9MUlRfMTkxMDI0ICAodW1p6KOc5q2j44Gq44GXLGZkcjAuMikgKFRQTSAxOTA3MjJ2ZXIpICgxOTA5MjTjgpLlhYPjgaspICgxOTA2MjctMTAyNCld44KS5Y+C6ICD44Gr44GX44Gf44CCCgojcHZhbHVlQ3V0b2ZmCQojcHZhbHVlIGN1dG9mZiBvbiBlbnJpY2htZW50IHRlc3RzIHRvIHJlcG9ydAoKI3BBZGp1c3RNZXRob2QJCiNvbmUgb2YgImhvbG0iLCAiaG9jaGJlcmciLCAiaG9tbWVsIiwgImJvbmZlcnJvbmkiLCAiQkgiLCAiQlkiLCAiZmRyIiwgIm5vbmUiCgojcXZhbHVlQ3V0b2ZmCQojcXZhbHVlIGN1dG9mZiBvbiBlbnJpY2htZW50IHRlc3RzIHRvIHJlcG9ydCBhcyBzaWduaWZpY2FudC4gVGVzdHMgbXVzdCBwYXNzIGkpIHB2YWx1ZUN1dG9mZiBvbiB1bmFkanVzdGVkIHB2YWx1ZXMsIGlpKSBwdmFsdWVDdXRvZmYgb24gYWRqdXN0ZWQgcHZhbHVlcyBhbmQgaWlpKSBxdmFsdWVDdXRvZmYgb24gcXZhbHVlcyB0byBiZSByZXBvcnRlZC4KCiMg6Kit5a6aKHB2YWx1ZUN1dG9mZiAgPSAwLjEsIHF2YWx1ZUN1dG9mZiAgPSAwLjIp44Gg44Go44CBcOWApDwwLjEsIHAuYWRqdXN05YCkPDAuMSwgceWApDwwLjIg44Gr44Gq44Gj44Gm44GE44KL44CCCgpgYGAKCkdP44GT44GT44G+44GnCgrjgZPjga7lvozjgavku6XliY3jga9mYW50b20144Gu44OH44O844K/44Gu44Kz44O844OJ44GM5YWl44Gj44Gm44GE44Gf44GM44CB44Kr44OD44OI44CCCm1vdXNlIENUWCAoQlJCIDA0MzgpIOOBrue1kOaenOOBqOOBruavlOi8g+OCguOCq+ODg+ODiAoKCgo=